Verification: a143cc29221c9be0

Php artisan storage link вручную

Введение

Контейнер служб (service container, сервис-контейнер) Laravel – это мощный инструмент для управления зависимостями классов и выполнения внедрения зависимостей. Внедрение зависимостей – это причудливая фраза, которая по существу означает следующее: зависимости классов «вводятся» в класс через конструктор в виде аргументов или, в некоторых случаях, через методы-сеттеры. При создании класса или вызове методов фреймворк смотрит на список аргументов и, если нужно, создаёт экземпляры необходимых классов и сам подаёт их на вход конструктора или метода.

Давайте посмотрим на простой пример:

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Repositories\UserRepository;
use App\Models\User;

class UserController extends Controller
{
    
    protected $users;

    
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

    
    public function show($id)
    {
        $user = $this->users->find($id);

        return view('user.profile', ['user' => $user]);
    }
}

В этом примере UserController необходимо получить пользователей из источника данных. Итак, мы внедрим службу, которая может получать пользователей. В этом контексте наш UserRepository, скорее всего, использует Eloquent для получения информации о пользователе из базы данных. Однако, поскольку репозиторий внедрен, мы можем легко заменить его другой реализацией. Мы также можем легко «имитировать» или создать фиктивную реализацию UserRepository при тестировании нашего приложения.

Глубокое понимание контейнера служб Laravel необходимо для создания большого, мощного приложения, а также для внесения вклада в само ядро Laravel.

Неконфигурируемое внедрение

Если класс не имеет зависимостей или зависит только от других конкретных классов (не интерфейсов), контейнер не нужно инструктировать о том, как создавать этот класс. Например, вы можете поместить следующий код в свой файл routes/web.php:

class Service
{
    
}

Route::get('/', function (Service $service) {
    die(get_class($service));
});

В этом примере, при посещении / вашего приложения, маршрут автоматически получит класс Service и внедрит его в обработчик вашего маршрута. Это меняет правила игры. Это означает, что вы можете разработать свое приложение и воспользоваться преимуществами внедрения зависимостей, не беспокоясь о раздутых файлах конфигурации.

К счастью, многие классы, которые вы будете писать при создании приложения Laravel, автоматически получают свои зависимости через контейнер, включая контроллеры, слушатели событий, посредники и т.д. Кроме того, вы можете объявить зависимости в методе handle заданиям в очередях. Как только вы почувствуете всю мощь автоматического неконфигурируемого внедрения зависимостей, вы почувствуете невозможность разработки без нее.

Когда использовать контейнер

Благодаря неконфигурируемому внедрению, вы часто будете объявлять типы зависимостей в маршрутах, контроллерах, слушателях событий и других местах, не взаимодействуя с контейнером напрямую. Например, вы можете указать объект Illuminate\Http\Request в определении вашего маршрута, чтобы вы могли легко получить доступ к текущему запросу. Несмотря на то, что нам никогда не нужно взаимодействовать с контейнером для написания этого кода, он управляет внедрением этих зависимостей за кулисами:

use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    
});

Во многих случаях, благодаря автоматическому внедрению зависимостей и фасадам, вы можете строить приложения Laravel без необходимости когда-либо вручную связывать или извлекать что-либо из контейнера. Итак, когда бы вы могли вручную взаимодействовать с контейнером?. Давайте рассмотрим две ситуации.

Во-первых, если вы пишете класс, реализующий интерфейс, и хотите объявить тип этого интерфейса в конструкторе маршрута или класса, вы должны сообщить контейнеру, как получить этот интерфейс. Во-вторых, если вы пишете пакет Laravel, которым планируете поделиться с другими разработчиками Laravel, вам может потребоваться связать службы вашего пакета в контейнере.

Связывание

Основы связываний

Простое связывание

Почти все ваши связывания в контейнере служб будут зарегистрированы в поставщиках служб, поэтому в большинстве этих примеров будет продемонстрировано использование контейнера в этом контексте.

Внутри поставщика служб у вас всегда есть доступ к контейнеру через свойство $this->app. Мы можем зарегистрировать связывание, используя метод bind, передав имя класса или интерфейса, которые мы хотим зарегистрировать, вместе с замыканием, возвращающем экземпляр класса:

use App\Services\Transistor;
use App\Services\PodcastParser;

$this->app->bind(Transistor::class, function ($app) {
    return new Transistor($app->make(PodcastParser::class));
});

Обратите внимание, что мы получаем сам контейнер в качестве аргумента. Затем мы можем использовать контейнер для извлечения под-зависимостей объекта, который мы создаем.

Как уже упоминалось, вы обычно будете взаимодействовать с контейнером внутри поставщиков служб; однако, если вы хотите взаимодействовать с контейнером вне поставщика услуг, вы можете сделать это через фасад App:

use App\Services\Transistor;
use Illuminate\Support\Facades\App;

App::bind(Transistor::class, function ($app) {
    
});
Нет необходимости привязывать классы в контейнере, если они не зависят от каких-либо интерфейсов. Контейнеру не нужно указывать, как создавать эти объекты, поскольку он может автоматически извлекать эти объекты с помощью рефлексии.

Связывание одиночек

Метод singleton связывает класс или интерфейс в контейнере, который должен быть извлечен только один раз. После получения одиночки, тот же экземпляр объекта будет возвращен из контейнера и при последующих вызовах:

use App\Services\Transistor;
use App\Services\PodcastParser;

$this->app->singleton(Transistor::class, function ($app) {
    return new Transistor($app->make(PodcastParser::class));
});

Связывание экземпляров

Вы также можете привязать существующий экземпляр объекта в контейнере, используя метод instance. Переданный экземпляр всегда будет возвращен из контейнера при последующих вызовах:

use App\Services\Transistor;
use App\Services\PodcastParser;

$service = new Transistor(new PodcastParser);

$this->app->instance(Transistor::class, $service);

Связывание интерфейсов и реализаций

Очень мощная функция контейнера служб – это его способность связывать интерфейс с конкретной реализацией. Например, предположим, что у нас есть интерфейс EventPusher и реализация RedisEventPusher. После того, как мы написали нашу реализацию RedisEventPusher этого интерфейса, мы можем зарегистрировать его в контейнере следующим образом:

use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;

$this->app->bind(EventPusher::class, RedisEventPusher::class);

Эта запись сообщает контейнеру, что он должен внедрить RedisEventPusher, когда классу требуется реализация EventPusher. Теперь мы можем указать интерфейс EventPusher в конструкторе класса, который будет извлечен контейнером. Помните, что контроллеры, слушатели событий, посредники и различные другие типы классов в приложениях Laravel всегда выполняются с помощью контейнера:

use App\Contracts\EventPusher;


public function __construct(EventPusher $pusher)
{
    $this->pusher = $pusher;
}

Контекстная привязка

Иногда, у вас может быть два класса, которые используют один и тот же интерфейс, но вы хотите внедрить разные реализации в каждый класс. Например, два контроллера могут зависеть от разных реализаций контракта Illuminate\Contracts\Filesystem\Filesystem. Laravel предлагает простой и понятный интерфейс для определения этого поведения:

use App\Http\Controllers\PhotoController;
use App\Http\Controllers\UploadController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;

$this->app->when(PhotoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('local');
          });

$this->app->when([VideoController::class, UploadController::class])
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('s3');
          });

Связывание примитивов

Иногда, у вас может быть класс, который получает некоторые внедренные классы, но также нуждается в примитиве, таком как целое число. Вы можете легко использовать контекстную привязку, чтобы внедрить любое значение, которое может понадобиться вашему классу:

$this->app->when('App\Http\Controllers\UserController')
          ->needs('$variableName')
          ->give($value);

Иногда, класс может зависеть от массива экземпляров, объединенных меткой. Используя метод giveTagged, вы можете легко их внедрить:

$this->app->when(ReportAggregator::class)
    ->needs('$reports')
    ->giveTagged('reports');

Если вам нужно внедрить значение из одного из конфигурационных файлов вашего приложения, то вы можете использовать метод giveConfig:

$this->app->when(ReportAggregator::class)
    ->needs('$timezone')
    ->giveConfig('app.timezone');

Связывание типизированных вариаций

Иногда у вас может быть класс, который получает массив типизированных объектов с использованием переменного количества аргументов (прим. перев.: далее «вариации») конструктора:

use App\Models\Filter;
use App\Services\Logger;

class Firewall
{
    
    protected $logger;

    
    protected $filters;

    
    public function __construct(Logger $logger, Filter ...$filters)
    {
        $this->logger = $logger;
        $this->filters = $filters;
    }
}

Используя контекстную привязку, вы можете внедрить такую зависимость, используя метод give с замыканием, которое возвращает массив внедряемых экземпляров Filter:

$this->app->when(Firewall::class)
          ->needs(Filter::class)
          ->give(function ($app) {
                return [
                    $app->make(NullFilter::class),
                    $app->make(ProfanityFilter::class),
                    $app->make(TooLongFilter::class),
                ];
          });

Для удобства вы также можете просто передать массив имен классов, которые будут предоставлены контейнером всякий раз, когда для Firewall нужны экземпляры Filter:

$this->app->when(Firewall::class)
          ->needs(Filter::class)
          ->give([
              NullFilter::class,
              ProfanityFilter::class,
              TooLongFilter::class,
          ]);

Метки вариативных зависимостей

Иногда класс может иметь вариативную зависимость, указывающую на тип как переданный класс (Report ...$reports). Используя методы needs и giveTagged, вы можете легко внедрить все привязки контейнера с этой меткой для указанной зависимости:

$this->app->when(ReportAggregator::class)
    ->needs(Report::class)
    ->giveTagged('reports');

Добавление меток

Иногда может потребоваться получить все привязки определенной «категории». Например, возможно, вы создаете анализатор отчетов, который получает массив из множества различных реализаций интерфейса Report. После регистрации реализаций Report вы можете назначить им метку с помощью метода tag:

$this->app->bind(CpuReport::class, function () {
    
});

$this->app->bind(MemoryReport::class, function () {
    
});

$this->app->tag([CpuReport::class, MemoryReport::class], 'reports');

После того, как службы помечены, вы можете легко все их получить с помощью метода tagged:

$this->app->bind(ReportAnalyzer::class, function ($app) {
    return new ReportAnalyzer($app->tagged('reports'));
});

Расширяемость связываний

Метод extend позволяет модифицировать извлеченные службы. Например, когда служба получена, вы можете запустить дополнительный код для декорирования или конфигурирования службы. Метод extend принимает замыкание, которое должно возвращать измененную службу в качестве единственного аргумента. Замыкание получает службу для извлечения и экземпляр контейнера:

$this->app->extend(Service::class, function ($service, $app) {
    return new DecoratedService($service);
});

Извлечение

Метод make

Вы можете использовать метод make для извлечения экземпляра класса из контейнера. Метод make принимает имя класса или интерфейса, который вы хотите получить:

use App\Services\Transistor;

$transistor = $this->app->make(Transistor::class);

Если некоторые зависимости вашего класса не могут быть разрешены через контейнер, вы можете ввести их, передав их как ассоциативный массив в метод makeWith. Например, мы можем вручную передать конструктору аргумент $id, требуемый службой Transistor:

use App\Services\Transistor;

$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);

Если вы находитесь за пределами поставщика служб и не имеете доступа к переменной $app, вы можете использовать фасад App для полуения экземпляра класса из контейнера:

use App\Services\Transistor;
use Illuminate\Support\Facades\App;

$transistor = App::make(Transistor::class);

Если вы хотите, чтобы сам экземпляр контейнера Laravel был внедрен в класс, извлекаемый контейнером, вы можете указать класс Illuminate\Container\Container в конструкторе вашего класса:

use Illuminate\Container\Container;


public function __construct(Container $container)
{
    $this->container = $container;
}

Автоматическое внедрение зависимостей

В качестве альтернативы, что важно, вы можете объявить тип зависимости в конструкторе класса, который извлекается контейнером, включая контроллеры, слушатели событий, посредники и т.д. Кроме того, вы можете объявить зависимости в методе handle заданиям в очередях. На практике именно так контейнер должен извлекать большинство ваших объектов.

Например, вы можете объявить репозиторий, определенный вашим приложением, в конструкторе контроллера. Репозиторий будет автоматически получен и внедрен в класс:

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    
    protected $users;

    
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

    
    public function show($id)
    {
        
    }
}

События контейнера

Контейнер служб инициирует событие каждый раз, когда извлекает объект. Вы можете прослушать это событие с помощью метода resolving:

use App\Services\Transistor;

$this->app->resolving(Transistor::class, function ($transistor, $app) {
    
});

$this->app->resolving(function ($object, $app) {
    
});

Как видите, извлекаемый объект будет передан в замыкание, что позволит вам установить любые дополнительные свойства объекта до того, как он будет передан его получателю.

Временна́я зона пользователя

У нас есть еще проблема с временно́й зоной — в базе данных мы храним дату и время в UTC. Будем показывать московское время для всех не аутентифицированных пользователй, а для аутентифицированных добавим возможность задать часовой пояс в личном кабинете. Мы добавим поле timezone в таблицу базы данных users и будем хранить в нем часовые пояса — Europe/Moscow, Asia/Irkutsk, Asia/Magadan.

> php artisan make:migration alter_users_table --table=users
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AlterUsersTable extends Migration {
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up() {
        Schema::table('users', function (Blueprint $table) {
            $table->string('timezone')->after('email')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down() {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('timezone');
        });
    }
}
> php artisan migrate
Migrating: 2021_02_26_074945_alter_users_table
Migrated:  2021_02_26_074945_alter_users_table (0.08 seconds)

Теперь в модели User, Post и Comment добавим аксессоры, которые будут изменять значения свойств моделей в момент доступа.

class User extends Authenticatable {
    /**
     * Преобразует дату и время регистрации пользователя из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getCreatedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if ($this->timezone) {
            $timezone = $this->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }

    /**
     * Преобразует дату и время обновления пользователя из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getUpdatedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if ($this->timezone) {
            $timezone = $this->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }
}
class Post extends Model {
    /**
     * Преобразует дату и время создания поста из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getCreatedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if (auth()->check() && auth()->user()->timezone) {
            $timezone = auth()->user()->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }

    /**
     * Преобразует дату и время обновления поста из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getUpdatedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if (auth()->check() && auth()->user()->timezone) {
            $timezone = auth()->user()->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }

    /**
     * Преобразует дату и время удаления поста из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getDeletedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if (auth()->check() && auth()->user()->timezone) {
            $timezone = auth()->user()->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }
}
class Comment extends Model {
    /**
     * Преобразует дату и время создания комментария из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getCreatedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if (auth()->check() && auth()->user()->timezone) {
            $timezone = auth()->user()->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }

    /**
     * Преобразует дату и время обновления комментария из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getUpdatedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if (auth()->check() && auth()->user()->timezone) {
            $timezone = auth()->user()->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }

    /**
     * Преобразует дату и время удаления комментария из UTC в Europe/Moscow
     *
     * @param $value
     * @return \Carbon\Carbon|false
     */
    public function getDeletedAtAttribute($value) {
        $timezone = 'Europe/Moscow';
        if (auth()->check() && auth()->user()->timezone) {
            $timezone = auth()->user()->timezone;
        }
        return Carbon::createFromFormat('Y-m-d H:i:s', $value)
            ->timezone($timezone)->format('d.m.Y H:i');
    }
}

Теперь в личном кабинете добавим возможность для пользователя указать свой часовой пояс. В модель User добавим константу TIMEZONES с перечислением всех часовых поясов России. И создадим форму с выпадающим списком, где пользователь сможет выбрать подходящую — и будем хранить зону для каждого пользователя в базе данных.

class User extends Authenticatable {
    /* ... */
    const TIMEZONES = [
        'Europe/Kaliningrad' => 'Калининград, Россия (+02:00)',
        'Europe/Moscow' => 'Москва, Россия (+03:00)',
        'Europe/Astrakhan' => 'Астрахань, Россия (+04:00)',
        'Asia/Yekaterinburg' => 'Екатеринбург, Россия (+05:00)',
        'Asia/Omsk' => 'Омск, Россия (+06:00)',
        'Asia/Novosibirsk' => 'Новосибирск, Россия (+07:00)',
        'Asia/Irkutsk' => 'Иркутск, Россия (+08:00)',
        'Asia/Chita' => 'Чита, Россия (+09:00)',
        'Asia/Vladivostok' => 'Владивосток, Россия (+10:00)',
        'Asia/Magadan' => 'Магадан, Россия (+11:00)',
        'Asia/Kamchatka' => 'Петропавловск-Камчатский, Россия (+12:00)'
    ];
    /* ... */
}

Два новых маршрута:

/*
 * Личный кабинет пользователя
 */
Route::group([
    'as' => 'user.', // имя маршрута, например user.index
    'prefix' => 'user', // префикс маршрута, например user/index
    'namespace' => 'User', // пространство имен контроллеров
    'middleware' => ['auth'] // один или несколько посредников
], function () {
    /* ..... */
    /*
     * Редактирование персональных данных
     */
    Route::get('edit/{user}', 'DataController@edit')->name('edit');
    Route::put('update/{user}', 'DataController@update')->name('update');
});

Новый контроллер:

> php artisan make:controller User/DataController
namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;

class DataController extends Controller {
    /**
     * Показывает форму для редактирования данных
     */
    public function edit(User $user) {
        $timezones = User::TIMEZONES;
        return view('user.data', compact('user', 'timezones'));
    }

    /**
     * Обновляет данные пользователя в базе данных
     */
    public function update(Request $request, User $user) {
        /*
         * Проверяем данные формы
         */
        $request->validate([
            'name' => 'string|required|max:255',
            'timezone' => 'nullable|string|max:255'
        ]);
        /*
         * Обновляем пользователя
         */
        $user->update($request->only(['name', 'timezone']));
        /*
         * Возвращаемся на главную
         */
        return redirect()
            ->route('user.index')
            ->with('success', 'Данные успешно обновлены');
    }
}

Шаблон user.data:

@extends('layout.user', ['title' => 'Личные данные'])

@section('content')
    

class

="mb-4">Личные данные
method
="post" action="{{ route('user.update', ['user' => $user->id]) }}"> @csrf @method('PUT')
class="form-group"> type="text" class="form-control" name="name" placeholder="Имя, Фамилия" required maxlength="255" value="{{ old('name') ?? $user->name }}">
class="form-group"> @php $timezone = old('timezone') ?? $user->timezone ?? null; @endphp ="timezone" class="form-control" title="Часовой пояс"> ="">Выберите @foreach($timezones as $key => $value) ="{{ $key }}" @if ($key === $timezone) selected @endif> {{ $value }} @endforeach
class="form-group"> ="submit" class="btn btn-success">Сохранить
@endsection

На главной странице личного кабинета разместим ссылку для перехода к редактированию личных данных:

@extends('layout.user', ['title' => 'Личный кабинет'])

@section('content')
    

Личный кабинет

Добрый день {{ auth()->user()->name }}! .......... href="{{ route('user.edit', ['user' => auth()->user()->id]) }}" class="btn btn-primary"> Личные данные @endsection

Методы фасада Storage

При использовании драйвера local все файловые операции выполняются относительно директории root, определенной в конфигурационном файле. Для диска local директория root — это storage/app, для диска public директория root — это storage/app/public.

// файл будет сохранен в storage/app/data/file.txt
Storage::disk('local')->put('data/file.txt', 'Some file content');

При вызове метода фасада Storage без предварительного вызова метода disk() — вызов будет автоматически передан диску по умолчанию.

// файл будет сохранен в storage/app/images/image.jpg
Storage::put('images/image.jpg', $contents); // содержимое файла
// файл будет сохранен в storage/app/images/image.jpg
Storage::put('images/image.jpg', $resource); // php-ресурс файла

Метод putFile() помещает содержимое указанного файла (в виде экземпляра класса Illuminate\Http\File или Illuminate\Http\UploadedFile) в указанный каталог, но с возложением контроля над всей потоковой обработкой и формированием уникального имени файла на Laravel. Метод возвращает путь к файлу, включая сформированное имя.

// автоматическое формирование уникального имени, файл будет сохранен
// как storage/app/images/L6ceLZQtmzvtR5lYEMqViu8BB8Fta8sWiD0xzXFw.jpeg
Storage::disk('local')->putFile('images', new File('/path/to/photo'));
// вручную указываем имя для, файл будет сохранен как storage/app/images/photo.jpg
Storage::disk('local')->putFileAs('images', new File('/path/to/photo'), 'photo.jpg');

Методом get() можно получать содержимое файла. Он возвращает сырую строку содержимого файла.

$contents = Storage::get('images/image.jpg');

Методом exists() можно определить существование файла на диске:

$exists = Storage::exists('image.jpg');

Метод url() позволяет получить URL файла. При использовании диска local будет возвращён URL вида /storage/images/image.jpg. При использовании диска public будет возвращён полный URL, домен сайта будет получен из .env-файла в корне проекта, это настройка APP_URL.

// возвращает URL /storage/images/image.jpg
$url = Storage::disk('local')->url('images/image.jpg');
// возвращает URL http://server.com/images/image.jpg
$url = Storage::disk('public')->url('images/image.jpg');

Метод size() позволяет получить размер файла в байтах:

$size = Storage::size('images/image.jpg');

Метод copy() копирует файл, метод move() перемещает файл:

Storage::copy('images/old-image.jpg', 'images/new-image.jpg');
Storage::move('images/old-image.jpg', 'images/new-image.jpg');

Метод prepend() добавляет содержимое в начало файла, метод append() добавляет содержимое в конец файла:

Storage::prepend('logs/some.log', 'Some log text');
Storage::append('logs/some.log', 'Some log text');

Метод delete() удаляет указанный файл:

Storage::delete('images/image.jpg');

Метод files() возвращает массив имен файлов в указанной директории. А метод allFiles() — массив имен файлов в указанной директории и во всех поддиректориях.

Метод directories() возвращает массив имен директорий в указанной директории. А метод allDirectories() — массив имен директорий в указанной директории и во всех поддиректориях.

Метод makeDirectory() создает новую директорию, а метод deleteDirectory() удаляет указанную директорию.