Manage File Attachments

Suggest Edit

This guide is a continuation of the tutorial “Data Management”, in which we will analyze the work with “Attached files”.

Let’s go back to the previously created Post model and add a new column hero, in which we will store information about the main image in our blog post:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->string('hero')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropColumn('hero');
        });
    }
}

Add to the model for automatic recording:

// app/Models/Post.php

protected $fillable = [
    'title',
    'description',
    'body',
    'author',
    'hero'
];
//..

To write data to a new column, you need to add a suitable field to our create/edit screen, take Cropper to crop the image:

// app/Orchid/Screens/PostEditScreen.php

public function layout(): array
{
    return [
        Layout::rows([
            Input::make('post.title')
                ->title('Title')
                ->placeholder('Attractive but mysterious title'),

            Cropper::make('post.hero')
                ->title('Large web banner image, generally in the front and center')
                ->width(1000)
                ->height(500),

            TextArea::make('post.description')
                ->title('Description')
                ->rows(3)
                ->maxlength(200)
                ->placeholder('Brief description for preview'),

            Relation::make('post.author')
                ->title('Author')
                ->fromModel(User::class, 'name'),

            Quill::make('post.body')
                ->title('Main text'),

        ])
    ];
}

Note. If during the file upload, you did not see your image in the end result, please check the upload_max_filesize and post_max_size settings, you may need to increase these values.

For such a field, the width and height were additionally indicated, in order to be sure the proportions are displayed to the user. After saving the record with the image, the full url address to the image will be written to the database column, for example:

http://localhost:8000/storage/2019/08/02/0f92ef693c26f3c1dbe2e3792abac9254ee98310.png

Note. The link to the image is formed from the url address specified in your configuration file, that for local development through the built-in web server, a port indication is required.

This is the easiest entry, but what if you decide to use https or change the domain? To do this, it is better to use a relative notation:

Cropper::make('post.hero')
    ->targetRelativeUrl(),

Another option for writing is to use relationships, for this the Cropper field will record the number of the downloaded file:

Cropper::make('post.hero')
    ->targetId(),

Note. In order for your database to be homogeneous, use one of the proposed options.

Let us dwell on the records of the number, but first, delete all existing records.

Most often, some files are combined, for example, for display in whole groups, the Upload field is suitable for this.

public function layout(): array
{
    return [
        Layout::rows([
            Input::make('post.title')
                ->title('Title')
                ->placeholder('Attractive but mysterious title'),

            Cropper::make('post.hero')
                ->targetId()
                ->title('Large web banner image, generally in the front and center')
                ->width(1000)
                ->height(500),

            TextArea::make('post.description')
                ->title('Description')
                ->rows(3)
                ->maxlength(200)
                ->placeholder('Brief description for preview'),

            Relation::make('post.author')
                ->title('Author')
                ->fromModel(User::class, 'name'),

            Quill::make('post.body')
                ->title('Main text'),

            Upload::make('post.attachments')
                ->title('All files')

        ])
    ];
}

The field will differ from the previous ones because the data does not apply explicitly to the Post model, but will be loaded and saved due to the connection, for this we must indicate the Attachable trait:

use Illuminate\Database\Eloquent\Model;
use Orchid\Attachment\Attachable;
use Orchid\Attachment\Models\Attachment;
use Orchid\Screen\AsSource;

class Post extends Model
{
    use AsSource, Attachable;
    //...
}

But also describe the synchronization of dependent records by relations in our screen:

public function createOrUpdate(Request $request)
{
    $this->post->fill($request->get('post'))->save();

    $this->post->attachments()->syncWithoutDetaching(
        $request->input('post.attachments', [])
    );

    Alert::info('You have successfully created a post.');

    return redirect()->route('platform.post.list');
}

After saving, the connection with our record will be established in the table attachmentable:

id  attachmentable_type  attachmentable_id  attachment_id
1	App\Post	         3	                101
2	App\Post	         3	                102
3	App\Post	         3	                103
4	App\Post	         3	                104

But when the record is accessed again, the field will be empty. This is due to the fact that query does not know about additional records to our model. We will fix this by adding a download:

public function query(Post $post): array
{
    $post->load('attachments');

    return [
        'post' => $post
    ];
}

Now our attached files are downloaded and synchronized. For more details, see the section “Form Elements” and “Attached Files”.

Our Friends