matthiasmullie/path-converter
Convert relative paths between source and target locations. Given a file currently relative to one path (e.g., an import), it returns the equivalent relative path from another path—useful for moving/minifying assets while keeping URLs correct.
Install the package via Composer:
composer require matthiasmullie/path-converter
First Use Case: Convert relative paths in CSS/JS files when moving them to a new directory structure.
use MatthiasMullie\PathConverter\Converter;
// Define source and target paths
$from = '/resources/css/styles.css';
$to = '/public/dist/styles.css';
// Create converter instance
$converter = new Converter($from, $to);
// Convert a relative path
$originalPath = '../../images/logo.png';
$convertedPath = $converter->convert($originalPath);
// $convertedPath now contains '../images/logo.png'
Where to Look First:
storage_path() and public_path() helpers for common path resolutionsPath Resolution: Convert Laravel's absolute paths to relative paths before passing to the converter
$from = str_replace(base_path(), '', storage_path('app/css/main.css'));
$to = str_replace(base_path(), '', public_path('dist/css/main.css'));
Asset Pipeline Integration: Use in Laravel Mix or custom build scripts
// mix.js
const converter = new Converter('/resources/css', '/public/dist/css');
Service Layer Pattern: Create a dedicated service class
class PathConverterService {
protected $converter;
public function __construct() {
$this->converter = new Converter(
$this->getSourcePath(),
$this->getTargetPath()
);
}
public function convertPath(string $path): string {
return $this->converter->convert($path);
}
}
1. Blade Template Processing
@php
$converter = new Converter(
str_replace(base_path(), '', storage_path('app/views/partials/header.blade.php')),
str_replace(base_path(), '', public_path('cached/views/header.blade.php'))
);
@endphp
<img src="{{ $converter->convert('images/logo.png') }}">
2. File Migration Utility
class FileMigrator {
public function migrate(string $sourceDir, string $targetDir): void {
$converter = new Converter($sourceDir, $targetDir);
foreach (glob($sourceDir . '/**/*') as $file) {
$relativePath = $converter->convert(str_replace($sourceDir, '', $file));
// Process migrated file with new path
}
}
}
3. Dynamic Path Conversion Middleware
public function handle($request, Closure $next) {
$converter = app()->make(Converter::class);
if ($request->has('asset_path')) {
$request->merge([
'converted_path' => $converter->convert($request->input('asset_path'))
]);
}
return $next($request);
}
4. Testing Helper
class PathConverterTestCase extends TestCase {
protected function convertPath(string $from, string $to, string $path): string {
return (new Converter($from, $to))->convert($path);
}
}
1. Configuration-Based Conversion
// config/path-converter.php
return [
'default' => [
'from' => env('PATH_CONVERTER_FROM', 'resources'),
'to' => env('PATH_CONVERTER_TO', 'public/dist'),
],
'custom' => [
'from' => 'storage/app',
'to' => 'public/uploads',
],
];
// Usage
$converter = new Converter(
config('path-converter.default.from'),
config('path-converter.default.to')
);
2. Facade Implementation
// app/Facades/PathConverter.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
use MatthiasMullie\PathConverter\Converter;
class PathConverter extends Facade {
protected static function getFacadeAccessor() {
return 'path.converter';
}
}
// app/Providers/AppServiceProvider.php
public function register() {
$this->app->singleton('path.converter', function() {
return new Converter(
config('path-converter.default.from'),
config('path-converter.default.to')
);
});
}
// Usage
use App\Facades\PathConverter;
$converted = PathConverter::convert('../../images/banner.jpg');
3. Artisan Command for Bulk Conversion
class ConvertPathsCommand extends Command {
protected $signature = 'paths:convert
{source : Source directory path}
{target : Target directory path}
{--file= : Specific file to convert}';
public function handle() {
$converter = new Converter($this->argument('source'), $this->argument('target'));
if ($file = $this->option('file')) {
$this->convertSingleFile($file, $converter);
} else {
$this->convertDirectory($this->argument('source'), $converter);
}
}
protected function convertSingleFile(string $file, Converter $converter) {
$content = file_get_contents($file);
$converted = preg_replace_callback(
'/url\(([\'"])(.*?)\1\)/',
fn($matches) => 'url('.$matches[1].$converter->convert($matches[2]).$matches[1].')',
$content
);
file_put_contents($file, $converted);
$this->info("Converted paths in {$file}");
}
}
1. Absolute Path Handling
// ❌ Problem: Absolute paths will break conversion
$converter = new Converter('/var/www/project/resources', '/var/www/project/public');
$result = $converter->convert('/var/www/project/images/logo.png');
// Returns '/var/www/project/public/var/www/project/images/logo.png'
// ✅ Solution: Use relative paths
$converter = new Converter('resources', 'public');
$result = $converter->convert('../images/logo.png');
// Returns '../images/logo.png'
2. Windows Path Separators
// ❌ Problem: Windows paths with backslashes
$converter = new Converter('C:\\project\\resources', 'C:\\project\\public');
$result = $converter->convert('..\\images\\logo.png');
// May not convert correctly
// ✅ Solution: Normalize paths
$converter = new Converter(
str_replace('\\', '/', 'C:/project/resources'),
str_replace('\\', '/', 'C:/project/public')
);
$result = $converter->convert('../images/logo.png');
// Returns '../images/logo.png'
3. Deep Directory Traversal
// ❌ Problem: Complex path with many ../
$converter = new Converter('resources/css', 'public/dist/css');
$result = $converter->convert('../../../../images/logo.png');
// May not resolve as expected
// ✅ Solution: Test thoroughly with edge cases
4. Case Sensitivity
// ❌ Problem: Case-sensitive filesystem
$converter = new Converter('Resources', 'Public');
$result = $converter->convert('../images/Logo.PNG');
// May not match actual filesystem paths
// ✅ Solution: Use consistent casing
1. Verify Path Structures
$from = realpath('resources/css');
$to = realpath('public/dist/css');
$converter = new Converter($from, $to);
2. Log Conversion Results
$original = 'some/relative/path';
$converted = $converter->convert($original);
Log::debug("Path conversion", [
'original' => $original,
'converted' => $converted,
'from' => $converter->getFrom(),
'to' => $converter->getTo()
]);
3. Test with Boundary Cases
$testCases = [
'file.txt',
'./file.txt',
'../file.txt',
'../../file.txt',
'/absolute/path/file.txt',
'file.txt/../file2.txt',
'file.txt/./file2.txt',
];
foreach ($testCases as $path) {
$result = $converter->convert($path);
// Verify results match expectations
}
1. Caching Converter Instances
// In service provider
$this->app->singleton(Converter::class, function() {
return new Converter(
config('path-converter.from'),
config('path-converter.to')
);
});
// Usage
$converter = app(Converter::class);
2. Batch Processing Optimization
public function convertMultiple(array $paths, Converter $converter): array {
return array_map(fn($path) => $converter->convert($path), $paths);
}
1. Custom Path Normalization
class CustomConverter extends Converter {
How can I help you explore Laravel packages today?