Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Path Generator Laravel Package

da-vinci-studio/path-generator

Generate consistent file and directory paths in your Laravel app with configurable patterns and helpers. Useful for organizing uploads, storage, and assets by date, model, or custom rules, keeping paths predictable and easy to change later.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require da-vinci-studio/path-generator
    

    Add to composer.json if not auto-loaded:

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "DavinciStudio\\PathGenerator\\": "vendor/da-vinci-studio/path-generator/src/"
        }
    }
    

    Run composer dump-autoload.

  2. Basic Usage:

    use DavinciStudio\PathGenerator\PathGenerator;
    
    $generator = new PathGenerator();
    $path = $generator->generate('app/storage/logs/{filename}.log');
    

    Replace {filename} with a dynamic value:

    $path = $generator->generate('app/storage/logs/{filename}.log', ['filename' => 'app']);
    // Output: "app/storage/logs/app.log"
    
  3. First Use Case: Generate filesystem paths dynamically for:

    • User uploads (app/storage/uploads/{user_id}/{filename}.{ext})
    • Log files (storage/logs/{service}.{date}.log)
    • Config overrides (config/{env}.php)

Implementation Patterns

Core Workflows

  1. Dynamic Path Generation:

    // Generate a path with placeholders
    $path = $generator->generate('app/storage/{type}/{id}/{filename}.{ext}', [
        'type' => 'uploads',
        'id' => 123,
        'filename' => 'profile',
        'ext' => 'png'
    ]);
    // Output: "app/storage/uploads/123/profile.png"
    
  2. Integration with Laravel:

    • Service Provider Binding:

      // app/Providers/AppServiceProvider.php
      public function register()
      {
          $this->app->singleton(PathGenerator::class, function ($app) {
              return new PathGenerator();
          });
      }
      

      Inject via constructor:

      public function __construct(private PathGenerator $pathGenerator) {}
      
    • Helper Function:

      // app/Helpers/path.php
      if (!function_exists('generate_path')) {
          function generate_path(string $template, array $data = []): string
          {
              return app(PathGenerator::class)->generate($template, $data);
          }
      }
      

      Usage:

      $path = generate_path('app/storage/{type}/{id}.json', ['type' => 'cache', 'id' => 1]);
      
  3. Path Validation:

    // Check if path is valid before generating files
    if ($generator->isValid('app/storage/{type}/{id}', ['type' => 'uploads', 'id' => 123])) {
        $path = $generator->generate('app/storage/{type}/{id}', ['type' => 'uploads', 'id' => 123]);
        Storage::put($path, $content);
    }
    
  4. Environment-Specific Paths:

    $path = $generator->generate(
        env('APP_ENV') === 'production'
            ? 'app/storage/prod/{filename}.log'
            : 'app/storage/dev/{filename}.log',
        ['filename' => 'debug']
    );
    

Advanced Patterns

  1. Path Templates as Config: Store templates in config/path_templates.php:

    return [
        'uploads' => 'app/storage/uploads/{user_id}/{filename}.{ext}',
        'logs' => 'storage/logs/{service}.{date}.log',
    ];
    

    Usage:

    $template = config('path_templates.uploads');
    $path = $generator->generate($template, ['user_id' => 1, 'filename' => 'avatar', 'ext' => 'jpg']);
    
  2. Path Generation in Controllers:

    public function store(Request $request)
    {
        $request->validate(['file' => 'required|file']);
        $file = $request->file('file');
    
        $path = $this->pathGenerator->generate(
            'app/storage/uploads/{user_id}/{filename}.{ext}',
            [
                'user_id' => auth()->id(),
                'filename' => Str::slug($file->getClientOriginalName()),
                'ext' => $file->getClientOriginalExtension(),
            ]
        );
    
        $file->storeAs('public', basename($path));
    }
    
  3. Path Generation in Models:

    class Upload extends Model
    {
        public function getPathAttribute(): string
        {
            return app(PathGenerator::class)->generate(
                'app/storage/uploads/{user_id}/{filename}.{ext}',
                [
                    'user_id' => $this->user_id,
                    'filename' => $this->filename,
                    'ext' => $this->extension,
                ]
            );
        }
    }
    
  4. Path Generation in Blade:

    // Add to Composer autoload (if not already)
    // composer.json: "autoload": { "files": ["app/Helpers/path.php"] }
    

    Blade usage:

    <img src="{{ generate_path('app/storage/uploads/{user_id}/{filename}.{ext}', [
        'user_id' => $user->id,
        'filename' => $upload->filename,
        'ext' => $upload->extension
    ]) }}">
    

Gotchas and Tips

Pitfalls

  1. Placeholder Case Sensitivity:

    • Templates are case-sensitive. {Filename}{filename}.
    • Fix: Standardize placeholder naming (e.g., snake_case).
  2. Missing Placeholders:

    • If a placeholder in the template isn’t provided in the data array, the path will include the literal placeholder (e.g., {filename}).
    • Fix: Validate placeholders exist in data:
      $requiredPlaceholders = ['filename', 'ext'];
      $missing = array_diff($requiredPlaceholders, array_keys($data));
      if (!empty($missing)) {
          throw new \InvalidArgumentException("Missing placeholders: " . implode(', ', $missing));
      }
      
  3. Path Traversal Risks:

    • Malicious input could inject ../ to escape directories.
    • Fix: Sanitize inputs or use realpath() to resolve paths:
      $path = $generator->generate($template, $data);
      $resolvedPath = realpath($path);
      if ($resolvedPath === false || strpos($resolvedPath, $path) !== 0) {
          throw new \RuntimeException("Invalid path resolution");
      }
      
  4. Deprecated Methods:

    • The package is outdated (last release 2016). Assume no active maintenance.
    • Fix: Fork and extend if critical features are missing.

Debugging Tips

  1. Enable Debug Output:

    $generator->setDebug(true);
    $path = $generator->generate('app/{type}/{id}', ['type' => 'storage', 'id' => 1]);
    // Outputs: "Replaced placeholders: ['type' => 'storage', 'id' => '1']"
    
  2. Log Generated Paths:

    $path = $generator->generate($template, $data);
    \Log::debug('Generated path', ['template' => $template, 'data' => $data, 'path' => $path]);
    
  3. Test Edge Cases:

    • Empty data array:
      $generator->generate('app/{type}', []); // Output: "app/{type}"
      
    • Nested placeholders:
      $generator->generate('app/{folder}/{subfolder}/{filename}', [
          'folder' => 'storage/{type}',
          'subfolder' => 'uploads',
          'filename' => 'file.txt',
          'type' => 'user'
      ]);
      // Output: "app/storage/user/uploads/file.txt"
      
      Note: Nested placeholders are resolved literally (not recursively).

Extension Points

  1. Custom Placeholder Handlers: Override placeholder logic by extending the class:

    class CustomPathGenerator extends \DavinciStudio\PathGenerator\PathGenerator
    {
        protected function replacePlaceholder(string $placeholder, string $value): string
        {
            // Custom logic (e.g., URL-encode values)
            return str_replace(' ', '-', $value);
        }
    }
    
  2. Add Path Validation Rules: Extend to validate paths against a whitelist:

    class ValidatedPathGenerator extends \DavinciStudio\PathGenerator\PathGenerator
    {
        private $allowedPaths = ['app/storage/uploads', 'app/storage/logs'];
    
        public function generate(string $template, array $data = []): string
        {
            $path = parent::generate($template, $data);
            $resolvedPath = realpath($path);
            $basePath = realpath(dirname($path));
    
            foreach ($this->allowedPaths as $allowed) {
                if (strpos($resolvedPath, $allowed) ===
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity