├── .php_cs.dist.php ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── docs └── images │ └── filesystem.jpg ├── src ├── Exceptions │ └── NamespaceNotFoundException.php ├── File.php ├── Stub.php └── StubsServiceProvider.php └── todo /.php_cs.dist.php: -------------------------------------------------------------------------------- 1 | in([ 5 | __DIR__ . '/src', 6 | __DIR__ . '/tests', 7 | ]) 8 | ->name('*.php') 9 | ->notName('*.blade.php') 10 | ->ignoreDotFiles(true) 11 | ->ignoreVCS(true); 12 | 13 | return ( new PhpCsFixer\Config() ) 14 | ->setRules( 15 | [ 16 | '@PSR12' => true, 17 | 'array_syntax' => ['syntax' => 'short'], 18 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 19 | 'braces' => [ 20 | 'allow_single_line_anonymous_class_with_empty_body' => true, 21 | ], 22 | 'no_unused_imports' => true, 23 | 'not_operator_with_successor_space' => true, 24 | 'trailing_comma_in_multiline' => true, 25 | 'phpdoc_scalar' => true, 26 | 'unary_operator_spaces' => true, 27 | 'binary_operator_spaces' => true, 28 | 'phpdoc_single_line_var_spacing' => true, 29 | 'phpdoc_var_without_name' => true, 30 | 'class_attributes_separation' => [ 31 | 'elements' => [ 32 | 'method' => 'one', 33 | ], 34 | ], 35 | 'method_argument_space' => [ 36 | 'on_multiline' => 'ensure_fully_multiline', 37 | 'keep_multiple_spaces_after_comma' => true, 38 | ], 39 | 'single_trait_insert_per_statement' => true, 40 | 'array_push' => true, 41 | 'backtick_to_shell_exec' => true, 42 | 'ereg_to_preg' => true, 43 | 'no_alias_language_construct_call' => true, 44 | 'no_mixed_echo_print' => true, 45 | 'pow_to_exponentiation' => true, 46 | 'random_api_migration' => true, 47 | 'set_type_to_cast' => true, 48 | 'array_indentation' => true, 49 | 'blank_line_before_statement' => [ 50 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try', 'do', 'exit', 'goto', 'if', 'switch', 'yield'], 51 | // Check for support with if conditions and early returns in a function 52 | ], 53 | 'compact_nullable_typehint' => true, 54 | 'heredoc_indentation' => true, 55 | 'line_ending' => true, 56 | 'method_chaining_indentation' => true, // Check for support with chained methods 57 | 'no_extra_blank_lines' => 58 | [ 59 | 'tokens' => ['continue', 'curly_brace_block', 'extra', 'return', 'parenthesis_brace_block', 'square_brace_block', 'throw', 'use', 'switch', 'case', 'default',], 60 | ], 61 | 'no_trailing_whitespace' => true, 62 | 'types_spaces' => [ 63 | 'space' => 'none', 64 | ], 65 | 'no_multiline_whitespace_around_double_arrow' => true, 66 | 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true], 67 | 'normalize_index_brace' => true, 68 | 'trim_array_spaces' => true, 69 | 'whitespace_after_comma_in_array' => true, 70 | ] 71 | ) 72 | ->setFinder($finder); 73 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `stubs` will be documented in this file. 4 | 5 | ## 1.4.0 - 2023-02-17 6 | 7 | - Add Laravel 10 support in #11 8 | 9 | ## 1.3.0 - 2022-01-20 10 | 11 | - Add Laravel 9 support 12 | 13 | ## 1.2.0 - 2022-01-18 14 | 15 | - Update this package to be called `ralphjsmit/filesystem` instead of `ralphjsmit/stubs` 16 | 17 | ## 1.1.0 - 2021-12-31 18 | 19 | - Changed return type of `delete()` method on `File` to be a boolean 20 | - Added `getDirectory()` method on `File` 21 | - Changed behaviour of `replaceNamespaces()` to return original object 22 | 23 | ## 1.0.0 - 2021-12-31 24 | 25 | - Initial release 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ralph J. Smit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Stubs Banner](https://github.com/ralphjsmit/filesystem/blob/main/docs/images/filesystem.jpg) 2 | 3 | # A fluent filesystem package for PHP 4 | 5 | This package helps you to speed up the process of moving and copying files. It also makes replacing namespaces much easier, thus making it an invaluable tool for heavy filesystem tasks. Enjoy! 6 | 7 | > [!IMPORTANT] 8 | > This package is only updated until Laravel 10. 9 | 10 | [⚡️ See the release article on my website or subscribe to my newsletter for an occasional update](https://ralphjsmit.com/php-fluent-filesystem-package/) 11 | 12 | ## Installation 13 | 14 | You can install the package via composer: 15 | 16 | ```bash 17 | composer require ralphjsmit/filesystem 18 | ``` 19 | 20 | ## Usage 21 | 22 | This package works by providing you with a base `Stub` class and a `File` class. As the name implies, the `Stub` class is an object that contains specific configuration, like the namespaces and the base directory. The `File` class is used to represent an individual file. 23 | 24 | ### Creating a Stub configuration 25 | 26 | You can create a new `Stub` configuration with `Stub::new()`: 27 | 28 | ```php 29 | use RalphJSmit\Filesystem\Stub; 30 | 31 | $stub = Stub::new(); 32 | ``` 33 | 34 | You can use a `Stub` configuration like this (I'll talk more about file actions below): 35 | 36 | ```php 37 | $stub->getFile(__DIR__ . '/tmp/testFileA.php')->move(__DIR__ . '/tmp/otherFolder'); 38 | ``` 39 | 40 | You can also set a base directory for your `Stub`: 41 | 42 | ```php 43 | $stub = Stub::dir(__DIR__); 44 | 45 | $stub->getFile('/tmp/testFileA.php')->move('/tmp/otherFolder'); 46 | ``` 47 | 48 | If you already have a `$stub` instance, you can configure namespaces on them. Those namespaces are used on the `File` object for the `->namespace()` action. It basically means that you define the directories for each namespace in your project. 49 | 50 | ```php 51 | $stubs = Stub::dir(__DIR__)->namespaces([ 52 | 'Support' => '/src/Support/', 53 | 'Domain' => '/src/Domain/', 54 | 'App' => '/src/App/', 55 | ]); 56 | 57 | $stubs->getFile('/tmp/TestFileA.php')->namespace('Support/Models'); 58 | // Moves __DIR__ . `/tmp/testFileA.php` to __DIR__ . `/src/Support/Models/testFileA.php`. 59 | ``` 60 | 61 | You can also have multiple stub configurations at the same time: 62 | 63 | ```php 64 | $stubA = Stub::dir(__DIR__ . '/src'); 65 | $stubB = Stub::dir(__DIR__ . '/app'); 66 | $stubC = Stub::dir(__DIR__ . '/tmp'); 67 | ``` 68 | 69 | ## Getting a File object 70 | 71 | You can get a `File` object by directly calling `file()` on the `Stub` class: 72 | 73 | ```php 74 | $file = Stub::file(__DIR__ . '/tmp/testFileA.php'); 75 | ``` 76 | 77 | You can also get a `File` object from a `$stub` instance: 78 | 79 | ```php 80 | $stub = Stub::dir(__DIR__); 81 | 82 | $file = $stub->getFile('/tmp/testFileA.php'); 83 | ``` 84 | 85 | ### Actions on a File object 86 | 87 | If you have a `File` object, you can perform the following actions on it: 88 | 89 | #### Copying a file 90 | 91 | You can copy a file to a new **directory** using the `copy()` function: 92 | 93 | ```php 94 | $file = Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->copy('/tmp/test'); 95 | // $file is now in __DIR__ . '/tmp/testFileA.php' AND in __DIR__ . '/tmp/test/testFileA.php' 96 | ``` 97 | 98 | #### Deleting a file 99 | 100 | You can delete a file using the `delete()` function: 101 | 102 | ```php 103 | Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->delete(); 104 | // returns true on success 105 | ``` 106 | 107 | #### Getting the basename of a file 108 | 109 | You can get the basename of a file using the `getBasename()` function: 110 | 111 | ```php 112 | Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->getBasename(); 113 | // 'testFileA.php' 114 | ``` 115 | 116 | #### Getting the directory location of a file 117 | 118 | You can get the location of the directory of a file using the `getDirectory()` function: 119 | 120 | ```php 121 | Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->getDirectory(); 122 | // __DIR__ . '/tmp' 123 | ``` 124 | 125 | #### Getting the full path of a file 126 | 127 | You can get the full path of a file using the `getFilepath()` function: 128 | 129 | ```php 130 | Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->getFilepath(); 131 | // __DIR__ . '/testFileA.php' 132 | ``` 133 | 134 | #### Getting the file contents 135 | 136 | You can get the contents of a file using the `getContents()` function: 137 | 138 | ```php 139 | $contents = Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->getContents(); 140 | ``` 141 | 142 | #### Moving a file 143 | 144 | You can move a file to a new **directory** using the `move()` function: 145 | 146 | ```php 147 | $file = Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->move('/tmp/test'); 148 | // $file is now in __DIR__ . '/tmp/test/testFileA.php' 149 | ``` 150 | 151 | #### Updating the namespace of a file 152 | 153 | You may update the namespace of a file and move it to the correct directory with the `namespace()` helper. This is ideal if you need to move a PHP-file to a new directory *and* update its namespace. I use this technique in the [ralphjsmit/tall-install](https://github.com/ralphjsmit/tall-install/) package. 154 | 155 | ```php 156 | $basePath = __DIR__; 157 | 158 | $stubs = Stub::dir($basePath)->namespaces([ 159 | 'Support' => '/src/Support/', 160 | 'Domain' => '/src/Domain/', 161 | 'App' => '/src/App/', 162 | ]); 163 | 164 | $stubs->getFile('/app/Console/Kernel.php')->namespace('Support\App\Console'); 165 | // file is not in __DIR__ . '/src/Support/App/Console/Kernel.php' 166 | ``` 167 | 168 | [Checkout a real-life example from one of my packages](https://github.com/ralphjsmit/tall-install/blob/main/src/Actions/DDD/UpdateFileStructureAction.php). 169 | 170 | #### Updating the contents of a file 171 | 172 | You may update the contents of a file with the `putFile()` method: 173 | 174 | ```php 175 | $newContents = 'Hello world!'; 176 | 177 | $file = Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->putFile($newContents); 178 | ``` 179 | 180 | You may also specify a new location for the file: 181 | 182 | ```php 183 | $newContents = 'Hello world!'; 184 | 185 | $file = Stub::dir(__DIR__)->getFile('/tmp/testFileA.php')->putFile($newContents, '/tmp/test/myFile.php'); 186 | // Will create a file with the "Hello world!" in __DIR__ . '/tmp/test/myFile.php` 187 | // Old file will still exist 188 | ``` 189 | 190 | If you just want to move or copy a file, you should use those methods. 191 | 192 | #### Updating the namespace of a file 193 | 194 | You may replace the namespace of a file with the `replaceNamespace($newNamespace)` method: 195 | 196 | ```php 197 | $file = Stub::dir(__DIR)->getFile('/tmp/test/MyClass.php'); 198 | 199 | $file->replaceNamespace('App\Models'); 200 | 201 | // $file will now have the namespace App\Models 202 | ``` 203 | 204 | ## General 205 | 206 | 🐞 If you spot a bug, please submit a detailed issue, and I'll try to fix it as soon as possible. 207 | 208 | 🔐 If you discover a vulnerability, please review [our security policy](../../security/policy). 209 | 210 | 🙌 If you want to contribute, please submit a pull request. All PRs will be fully credited. If you're unsure whether I'd accept your idea, feel free to contact me! 211 | 212 | 🙋‍♂️ [Ralph J. Smit](https://ralphjsmit.com) 213 | 214 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "ralphjsmit/filesystem", 3 | "description" : "A fluent filesystem package for PHP.", 4 | "keywords" : [ 5 | "ralphjsmit", 6 | "laravel", 7 | "filesystem" 8 | ], 9 | "homepage" : "https://github.com/ralphjsmit/filesystem", 10 | "license" : "MIT", 11 | "authors" : [ 12 | { 13 | "name" : "Ralph J. Smit", 14 | "email" : "rjs@ralphjsmit.com", 15 | "role" : "Developer" 16 | } 17 | ], 18 | "require" : { 19 | "php" : "^8.0", 20 | "illuminate/contracts" : "^8.73|^9.0|^10.0", 21 | "spatie/laravel-package-tools" : "^1.11.0", 22 | "symfony/finder" : "^5.4|^6.0" 23 | }, 24 | "require-dev" : { 25 | "nesbot/carbon" : "^2.66", 26 | "nunomaduro/collision" : "^5.10|^6.0|^7.0", 27 | "orchestra/testbench" : "^6.23|^7.0|^8.0", 28 | "pestphp/pest" : "^1.21", 29 | "pestphp/pest-plugin-laravel" : "^1.1", 30 | "phpunit/phpunit" : "^9.5|^10.0", 31 | "spatie/laravel-ray" : "^1.26", 32 | "ralphjsmit/pest-plugin-filesystem" : "^1.0" 33 | }, 34 | "autoload" : { 35 | "psr-4" : { 36 | "RalphJSmit\\Filesystem\\" : "src", 37 | "RalphJSmit\\Filesystem\\Database\\Factories\\" : "database/factories" 38 | } 39 | }, 40 | "autoload-dev" : { 41 | "psr-4" : { 42 | "RalphJSmit\\Filesystem\\Tests\\" : "tests" 43 | } 44 | }, 45 | "scripts" : {}, 46 | "config" : { 47 | "sort-packages" : true, 48 | "allow-plugins" : { 49 | "pestphp/pest-plugin" : true 50 | } 51 | }, 52 | "extra" : { 53 | "laravel" : { 54 | "providers" : [ 55 | "RalphJSmit\\Filesystem\\StubsServiceProvider" 56 | ], 57 | "aliases" : {} 58 | } 59 | }, 60 | "minimum-stability" : "dev", 61 | "prefer-stable" : true, 62 | "repositories" : [] 63 | } 64 | -------------------------------------------------------------------------------- /docs/images/filesystem.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ralphjsmit/filesystem/de259d95bdc6caed60644a8c8868d744151205f1/docs/images/filesystem.jpg -------------------------------------------------------------------------------- /src/Exceptions/NamespaceNotFoundException.php: -------------------------------------------------------------------------------- 1 | putInFolder($destinationPath, $this->getContents()); 20 | 21 | return new static( 22 | filepath : $destinationPath . '/' . $this->getBasename(), 23 | basepath : $this->basepath, 24 | namespaces: $this->namespaces, 25 | ); 26 | } 27 | 28 | public function delete(): bool 29 | { 30 | return unlink($this->basepath . $this->filepath); 31 | } 32 | 33 | public function getBasename(): string 34 | { 35 | return basename($this->filepath); 36 | } 37 | 38 | public function getBasepath(): string 39 | { 40 | return $this->basepath; 41 | } 42 | 43 | public function getContents(): string 44 | { 45 | return file_get_contents($this->basepath . $this->filepath); 46 | } 47 | 48 | public function getDirectory(): string 49 | { 50 | return dirname($this->filepath); 51 | } 52 | 53 | public function getFilepath(): string 54 | { 55 | return $this->filepath; 56 | } 57 | 58 | public function getNamespaces(): array 59 | { 60 | return $this->namespaces; 61 | } 62 | 63 | public function move(string $destinationFolder): static 64 | { 65 | $newFile = $this->putFile( 66 | $this->getContents(), 67 | rtrim($destinationFolder, '/') . '/' . $this->getBasename() 68 | ); 69 | 70 | $this->delete(); 71 | 72 | return $newFile; 73 | } 74 | 75 | public function namespace(string $namespace): static 76 | { 77 | $namespaceSubfolder = Str::of($namespace)->after('\\')->replace('\\', '/'); 78 | 79 | $namespaceRoot = $this->namespaces[Str::before($namespace, '\\')] ?? throw new NamespaceNotFoundException(); 80 | $target = $this->putInFolder( 81 | $namespaceRoot . $namespaceSubfolder 82 | )->replaceNamespace(Str::of($namespace)); 83 | 84 | $this->delete(); 85 | 86 | return $target; 87 | } 88 | 89 | public function putFile(mixed $contents, string $destinationPath = null): static 90 | { 91 | if (! $destinationPath) { 92 | $destinationPath = $this->filepath; 93 | } 94 | 95 | if (! file_exists(dirname($this->basepath . $destinationPath))) { 96 | mkdir(dirname($this->basepath . $destinationPath), 0777, true); 97 | } 98 | 99 | file_put_contents($this->basepath . $destinationPath, $contents); 100 | 101 | return new static( 102 | filepath : $destinationPath, 103 | basepath : $this->basepath, 104 | namespaces: $this->namespaces, 105 | ); 106 | } 107 | 108 | public function putInFolder(string $destinationFolder, mixed $contents = null): static 109 | { 110 | return $this->putFile( 111 | $contents ?? $this->getContents(), 112 | rtrim($destinationFolder, '/') . '/' . $this->getBasename() 113 | ); 114 | } 115 | 116 | public function replaceNamespace(string $namespace): static 117 | { 118 | $contents = $this->getContents(); 119 | 120 | $contents = Str::replaceFirst( 121 | Str::of($contents)->after('namespace ')->before(';'), 122 | $namespace, 123 | $contents 124 | ); 125 | 126 | $this->putFile($contents); 127 | 128 | return $this; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Stub.php: -------------------------------------------------------------------------------- 1 | basepath; 28 | } 29 | 30 | public function getFile(string $filepath): File 31 | { 32 | return new File( 33 | filepath : $filepath, 34 | basepath : $this->basepath, 35 | namespaces: $this->namespaces, 36 | ); 37 | } 38 | 39 | public function getNamespaces(): array 40 | { 41 | return $this->namespaces; 42 | } 43 | 44 | public function namespaces(array $namespaces): static 45 | { 46 | $this->namespaces = array_merge( 47 | $this->namespaces, 48 | collect($namespaces)->mapWithKeys(function ($folder, $namespace) { 49 | return [$namespace => rtrim($folder, '/') . '/']; 50 | })->all() 51 | ); 52 | 53 | return $this; 54 | } 55 | 56 | public static function new(array $namespaces = []): static 57 | { 58 | return new static( 59 | namespaces: $namespaces, 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/StubsServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('stubs'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | - Update symfony/finder component to v6 after Laravel 9 release --------------------------------------------------------------------------------