Browse Source

add composer.json and .gitignore

olinox14 1 year ago
parent
commit
a40d72d0c4
4 changed files with 402 additions and 5 deletions
  1. 1 0
      .gitignore
  2. 1 0
      .idea/path.iml
  3. 1 1
      composer.json
  4. 399 4
      src/Path/Path.php

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+.idea/*

+ 1 - 0
.idea/path.iml

@@ -3,6 +3,7 @@
   <component name="NewModuleRootManager">
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Path\" />
+      <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="Path\Tests\" />
     </content>
     <orderEntry type="inheritedJdk" />

+ 1 - 1
composer.json

@@ -1,6 +1,6 @@
 {
   "name": "olinox14/path",
-  "description": "Simple, intuitive and object-oriented file and path operations, inspired by the path?py python library",
+  "description": "Simple, intuitive and object-oriented file and path operations, inspired by the path.py python library",
   "type": "library",
   "license": "MIT",
   "authors": [

+ 399 - 4
src/Path/Path.php

@@ -2,8 +2,20 @@
 
 namespace Path\Path;
 
+use InvalidArgumentException;
+
+/**
+ * Represents a file or directory path.
+ *
+ * @package olinox14/path
+ */
 class Path
 {
+    const F_OK = 0; // Check existence of the file
+    const R_OK = 4; // Check read permission of the file
+    const W_OK = 2; // Check write permission of the file
+    const X_OK = 1; // Check execute permission of the file
+
     protected string $path;
 
     public function __construct(string $path)
@@ -11,6 +23,76 @@ class Path
         $this->path = $path;
     }
 
+    public function append(string ...$parts): self
+    {
+        $this->path = join(DIRECTORY_SEPARATOR, array_merge([$this->path], $parts));
+        return $this;
+    }
+
+    /**
+     * Combine this path with one or several arguments
+     *
+     * @param string ...$parts
+     * @return string
+     */
+    public function joinpath(string ...$parts): string
+    {
+        return join(DIRECTORY_SEPARATOR, $parts);
+    }
+
+
+//    AI Generated below
+
+    /**
+     * Returns an absolute version of this path.
+     *
+     * @param string $path
+     * @return string
+     */
+    public function abspath(string $path): string
+    {
+        return realpath($path);
+    }
+
+    /**
+     * Checks the access rights for a given file or directory.
+     *
+     * @param string $path The path to the file or directory.
+     * @param int $mode The access mode to check. Permitted values:
+     *        - F_OK: checks for the existence of the file or directory.
+     *        - R_OK: checks for read permission.
+     *        - W_OK: checks for write permission.
+     *        - X_OK: checks for execute permission.
+     * @return bool Returns true if the permission check is successful; otherwise, returns false.
+     * @throws InvalidArgumentException Throws an exception if an invalid mode is provided.
+     */
+    function access(string $path, int $mode): bool
+    {
+        return match ($mode) {
+            self::F_OK => file_exists($path),
+            self::R_OK => is_readable($path),
+            self::W_OK => is_writable($path),
+            self::X_OK => is_executable($path),
+            default => throw new InvalidArgumentException('Invalid mode'),
+        };
+    }
+
+    /**
+     * Retrieves the last access time of a file or directory.
+     *
+     * @param string $path The path to the file or directory.
+     *
+     * @return string|null The last access time of the file or directory in 'Y-m-d H:i:s' format. Returns null if the file or directory does not exist or on error.
+     */
+    function atime(string $path): ?string
+    {
+        $time = fileatime($path);
+        if ($time === false) {
+            return null;
+        }
+        return date('Y-m-d H:i:s', $time);
+    }
+
     /**
      * Resolve the path.
      *
@@ -97,8 +179,7 @@ class Path
     {
         if (is_file($this->path)) {
             unlink($this->path); //for file
-        }
-        else if (is_dir($this->path)) {
+        } else if (is_dir($this->path)) {
             rmdir($this->path); //for directory
         }
     }
@@ -114,8 +195,7 @@ class Path
     {
         if (is_file($this->path)) {
             copy($this->path, $destination);
-        }
-        else if (is_dir($this->path)) {
+        } else if (is_dir($this->path)) {
             // Copy dir needs special handling, not covered in this example.
         }
     }
@@ -240,4 +320,319 @@ class Path
     {
         return file_exists($this->path);
     }
+
+    public static function glob(string $pattern)
+    {
+        foreach (glob($pattern) as $filename) {
+            yield new static($filename);
+        }
+    }
+
+    public function rmdir()
+    {
+        if (!is_dir($this->path)) {
+            throw new \RuntimeException("{$this->path} is not a directory");
+        }
+
+        $it = new RecursiveDirectoryIterator($this->path, RecursiveDirectoryIterator::SKIP_DOTS);
+        $files = new RecursiveIteratorIterator($it,
+            RecursiveIteratorIterator::CHILD_FIRST);
+
+        foreach ($files as $file) {
+            if ($file->isDir()) {
+                rmdir($file->getRealPath());
+            } else {
+                unlink($file->getRealPath());
+            }
+        }
+        rmdir($this->path);
+    }
+
+    public function open(string $mode = 'r')
+    {
+        if (!$this->isFile()) {
+            throw new \RuntimeException("{$this->path} is not a file");
+        }
+
+        $handle = fopen($this->path, $mode);
+        if ($handle === false) {
+            throw new \RuntimeException("Failed opening file {$this->path}");
+        }
+
+        return $handle;
+    }
+
+    /**
+     * Returns this path as a URI.
+     *
+     * @return string
+     */
+    public function as_uri(): string
+    {
+        throw new \Exception("Method not implemented");
+    }
+
+    /**
+     * Returns the group that owns the file.
+     *
+     * @return string
+     */
+    public function group(): string
+    {
+        throw new \Exception("Method not implemented");
+    }
+
+    /**
+     * Check whether this path is absolute.
+     *
+     * @return bool
+     */
+    public function is_absolute(): bool
+    {
+        return substr($this->path, 0, 1) === '/';
+    }
+
+    /**
+     * (Not supported in PHP). In Python, this would convert the path to POSIX style, but in PHP there's no equivalent.
+     * Therefore throwing an exception.
+     *
+     * @throws \RuntimeException
+     */
+    public function as_posix(): void
+    {
+        throw new \RuntimeException("Method 'as_posix' not supported in PHP");
+    }
+
+    /**
+     * Changes permissions of the file.
+     *
+     * @param int $mode The new permissions (octal).
+     * @return bool
+     */
+    public function chmod(int $mode): bool
+    {
+        return chmod($this->path, $mode);
+    }
+
+    /**
+     * Changes ownership of the file.
+     *
+     * @param string $user The new owner username.
+     * @param string $group The new owner group name.
+     * @return bool
+     */
+    public function chown(string $user, string $group): bool
+    {
+        return chown($this->path, $user) && chgrp($this->path, $group);
+    }
+
+    /**
+     * Checks if file is a block special file.
+     *
+     * @return bool
+     */
+    public function is_block_device(): bool
+    {
+        return function_exists('posix_isatty') && is_file($this->path) && posix_isatty($this->path);
+    }
+
+    /**
+     * Checks if file is a character special file.
+     *
+     * @return bool
+     */
+    public function is_char_device(): bool
+    {
+        return function_exists('filetype') && filetype($this->path) === 'char';
+    }
+
+    /**
+     * Checks if file is a Named Pipe (FIFO) special file.
+     *
+     * @return bool
+     */
+    public function is_fifo(): bool
+    {
+        return function_exists('filetype') && filetype($this->path) === 'fifo';
+    }
+
+    /**
+     * Checks if file is a socket.
+     *
+     * @return bool
+     */
+    public function is_socket(): bool
+    {
+        return function_exists('filetype') && 'socket' === filetype($this->path);
+    }
+
+    /**
+     * Checks if the file is a symbolic link.
+     *
+     * @return bool
+     */
+    public function is_symlink(): bool
+    {
+        return is_link($this->path);
+    }
+
+    /**
+     * Iterate over the files in this directory.
+     *
+     * @return \Generator
+     * @throws \RuntimeException if the path is not a directory.
+     */
+    public function iterdir()
+    {
+        if (!$this->isDir()) {
+            throw new \RuntimeException("{$this->path} is not a directory");
+        }
+
+        foreach (new \DirectoryIterator($this->path) as $fileInfo) {
+            if ($fileInfo->isDot()) continue;
+            yield $fileInfo->getFilename();
+        }
+    }
+
+
+
+    /**
+     * Change the mode of path to the numeric mode.
+     * This method does not follow symbolic links.
+     *
+     * @param int $mode
+     * @return bool
+     */
+    public function lchmod(int $mode): bool
+    {
+        if (!function_exists('lchmod')) {
+            return false;
+        }
+        return lchmod($this->path, $mode);
+    }
+
+    /**
+     * Change the owner and group id of path to the numeric uid and gid.
+     * This method does not follow symbolic links.
+     *
+     * @param int $uid User id
+     * @param int $gid Group id
+     * @return bool
+     */
+    public function lchown(int $uid, int $gid): bool
+    {
+        if (!function_exists('lchown')) {
+            return false;
+        }
+        return lchown($this->path, $uid) && lchgrp($this->path, $gid);
+    }
+
+    /**
+     * Create a hard link pointing to a path.
+     *
+     * @param string $target
+     * @return bool
+     */
+    public function link_to(string $target): bool
+    {
+        if (!function_exists('link')) {
+            return false;
+        }
+        return link($this->path, $target);
+    }
+
+    /**
+     * Like stat(), but do not follow symbolic links.
+     *
+     * @return array|false
+     */
+    public function lstat()
+    {
+        return lstat($this->path);
+    }
+
+    /**
+     * Returns the individual parts of this path.
+     *
+     * @return array
+     */
+    public function parts(): array
+    {
+        $separator = DIRECTORY_SEPARATOR;
+        return explode($separator, $this->path);
+    }
+
+    /**
+     * Opens the file in bytes mode, reads it, and closes the file.
+     *
+     * @return string
+     * @throws \RuntimeException
+     */
+    public function read_bytes(): string
+    {
+        $bytes = file_get_contents($this->path, FILE_BINARY);
+        if ($bytes === false) {
+            throw new \RuntimeException("Error reading file {$this->path}");
+        }
+
+        return $bytes;
+    }
+
+    /**
+     * Open the file in text mode, read it, and close the file
+     *
+     * @return string
+     * @throws \RuntimeException
+     */
+    public function read_text(): string
+    {
+        $text = file_get_contents($this->path);
+        if ($text === false) {
+            throw new \RuntimeException("Error reading file {$this->path}");
+        }
+
+        return $text;
+    }
+
+    /**
+     * Compute a version of this path that is relative to another path.
+     *
+     * @return string
+     * @throws \RuntimeException
+     */
+    public function relative_to(string $other_path): string
+    {
+        $path = $this->absolute();
+        $other = realpath($other_path);
+        if ($other === false) {
+            throw new \RuntimeException("$other_path does not exist or unable to get a real path");
+        }
+
+        $path_parts = explode(DIRECTORY_SEPARATOR, $path);
+        $other_parts = explode(DIRECTORY_SEPARATOR, $other);
+
+        while (count($path_parts) && count($other_parts) && ($path_parts[0] == $other_parts[0])) {
+            array_shift($path_parts);
+            array_shift($other_parts);
+        }
+
+        return str_repeat('..' . DIRECTORY_SEPARATOR, count($other_parts)) . implode(DIRECTORY_SEPARATOR, $path_parts);
+    }
+
+    /**
+     * Renames this file or directory to the given target.
+     *
+     * @param string $target
+     * @return bool
+     * @throws \RuntimeException
+     */
+    public function rename(string $target): bool
+    {
+        // Check if file or directory exists
+        if (!$this->isFile() && !$this->isDir()) {
+            throw new \RuntimeException("{$this->path} does not exist");
+        }
+
+        return rename($this->path, $target);
+    }
 }