Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 71 additions & 23 deletions docs/docs/4.0/auth/profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@

[[toc]]

To ensure you can get your profile, you should add the `Authenticate` middleware to your restify, this can be easily done by using the `Binaryk\LaravelRestify\Http\Middleware\RestifySanctumAuthenticate::class` into your `restify.middleware` [configuration file](../quickstart.html#configurations);
To ensure you can get your profile, you should add the `Authenticate` middleware to your restify, this can be easily
done by using the `Binaryk\LaravelRestify\Http\Middleware\RestifySanctumAuthenticate::class` into
your `restify.middleware` [configuration file](../quickstart.html#configurations);

Laravel Restify expose the user profile via `GET: /api/restify/profile` endpoint.

## Get profile using repository

When retrieving the user profile, by default it is serialized using the `UserRepository` if there is once (Restify will find the repository based on the `User` model).
When retrieving the user profile, by default it is serialized using the `UserRepository` if there is once (Restify will
find the repository based on the `User` model).

```http request
GET: /api/restify/profile
```

This is what we have for a basic profile:
This is what we have for a basic profile:

```json
{
Expand Down Expand Up @@ -51,7 +54,8 @@ public function fields(RestifyRequest $request)
}
```

Since the profile is resolved using the UserRepository, you can benefit from the power of related entities. For example, if you want to return user roles:
Since the profile is resolved using the UserRepository, you can benefit from the power of related entities. For example,
if you want to return user roles:

```php
//UserRepository
Expand All @@ -61,7 +65,8 @@ public static $related = [
];
```

And make sure the `User` model, has this method, which returns a relationship from another table, or you can simply return an array:
And make sure the `User` model, has this method, which returns a relationship from another table, or you can simply
return an array:

```php
//User.php
Expand All @@ -81,6 +86,7 @@ Let's get the profile now, using the `roles` relationship:
```http request
GET: /api/restify/profile?related=roles
```

The result will look like this:

```json
Expand Down Expand Up @@ -108,7 +114,8 @@ The result will look like this:

### Without repository

In some cases, you may choose to not use the repository for the profile serialization. In such cases you should add the trait `Binaryk\LaravelRestify\Repositories\UserProfile` into your `UserRepository`:
In some cases, you may choose to not use the repository for the profile serialization. In such cases you should add the
trait `Binaryk\LaravelRestify\Repositories\UserProfile` into your `UserRepository`:

```php
// UserProfile
Expand All @@ -127,7 +134,7 @@ class UserRepository extends Repository

In this case, the profile will return the model directly:

:::warn Relations
:::warning Relations
Note that when you're not using the repository, the `?related` will do not work anymore.
:::

Expand All @@ -150,10 +157,10 @@ And you will get:
}
```

### Conditionally use repository

In rare cases you may want to utilize the repository only for non admin users for example, to ensure you serialize specific fields for the users:
### Conditionally use repository

In rare cases you may want to utilize the repository only for non admin users for example, to ensure you serialize
specific fields for the users:

```php
use Binaryk\LaravelRestify\Fields\Field;
Expand Down Expand Up @@ -190,7 +197,8 @@ This way you instruct Restify to only use the repository for users who are admin

## Update Profile using repository

By default, Restify will validate, and fill only fields presented in your `UserRepository` for updating the user profile. Let's get as an example the following repository fields:
By default, Restify will validate, and fill only fields presented in your `UserRepository` for updating the user
profile. Let's get as an example the following repository fields:

```php
// UserRepository
Expand All @@ -215,8 +223,9 @@ If we will try to call the `PUT` method to update the profile without data:

We will get back `4xx` validation:

:::warn Accept header
If you test it via Postman (or other HTTP client), make sure you always pass the `Accept` header `application/json`. This will instruct Laravel to return you back json formatted data:
:::warning
Accept header If you test it via Postman (or other HTTP client), make sure you always pass the `Accept`
header `application/json`. This will instruct Laravel to return you back json formatted data:
:::

```json
Expand All @@ -229,6 +238,7 @@ If you test it via Postman (or other HTTP client), make sure you always pass the
}
}
```

So we have to populate the user `name` in the payload:

```json
Expand All @@ -237,7 +247,7 @@ So we have to populate the user `name` in the payload:
}
```

Since the payload is valid now, Restify will update the user profile (name in our case):
Since the payload is valid now, Restify will update the user profile (name in our case):

```json
{
Expand All @@ -258,7 +268,8 @@ Since the payload is valid now, Restify will update the user profile (name in ou

### Update without repository

If you [don't use the repository](./#get-profile-using-repository) for the user profile, Restify will update only `fillable` user attributes present in the request payload: `$request->only($user->getFillable())`.
If you [don't use the repository](./#get-profile-using-repository) for the user profile, Restify will update
only `fillable` user attributes present in the request payload: `$request->only($user->getFillable())`.

```http request
PUT: /api/restify/profile
Expand All @@ -272,7 +283,7 @@ Payload:
}
````

The response will be the updated user:
The response will be the updated user:

```json
{
Expand All @@ -289,7 +300,7 @@ The response will be the updated user:

## User avatar

To prepare your users for avatars, you should add the `avatar` column in your users table:
To prepare your users for avatars, you can add the `avatar` column in your users table:

```php
// Migration
Expand All @@ -301,23 +312,60 @@ public function up()
}
```

Now you can use the Restify endpoints to update the avatar:
Not you should specify in the user repository that user has avatar file:

```php
use Binaryk\LaravelRestify\Fields\Image;

public function fields(RestifyRequest $request)
{
return [
Field::make('name')->rules('required'),

Image::make('avatar')->storeAs('avatar.jpg')
];
}
```

Now you can use the Restify profile update, and give the avatar as an image.

:::warning Post request

You cannot upload file using PUT or PATCH verbs, so we should use POST request.
:::

```http request
POST: /api/restify/profile/avatar
POST: /api/restify/profile
```

The payload should be a form-data, with an image under `avatar` key:

```json
{
"avatar": "binary image in form data request"
}
```

The payload should be a form-data, with an image under `avatar` key.
If you have to customize path or disk of the storage file, check the [image field](../repository-pattern/field.html#file-fields)

### Avatar without repository

If you don't use the repository for updating the user profile, Restify provides a separate endpoint for updating the avatar.

```http request
POST: api/restify/profile/avatar
```

The default path for storing avatar is: `/avatars/{user_key}/`.
The default path for storing avatar is: `/avatars/{user_key}/`, and it uses by default the `public` disk.

You can modify that by modifying property in a `boot` method of any service provider:

```php
Binaryk\LaravelRestify\Http\Requests\ProfileAvatarRequest::$path
Binaryk\LaravelRestify\Http\Requests\ProfileAvatarRequest::$path = 'users';
Binaryk\LaravelRestify\Http\Requests\ProfileAvatarRequest::$disk = 's3';
```

Or if you need the request to make the path:
Or if you need the request to make the path:

```php
Binaryk\LaravelRestify\Http\Requests\ProfileAvatarRequest::usingPath(function(Illuminate\Http\Request $request) {
Expand Down
155 changes: 154 additions & 1 deletion docs/docs/4.0/repository-pattern/field.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Field

[[toc]]

Field is basically the model attribute representation. Each Field generally extends the `Binaryk\LaravelRestify\Fields\Field` class from the Laravel Restify.
This class ships a variety of mutators, interceptors, validators chaining methods you can use for defining your attribute.

Expand Down Expand Up @@ -198,7 +200,158 @@ Field::new('token')->value(Str::random(32))->hidden();

# Variations

Bellow we have a list of fields used for the related resources.
## File fields

To illustrate the behavior of Restify file upload fields, let's assume our application's users can upload "avatar photos" to their account. So, our users database table will have an `avatar` column. This column will contain the path to the profile on disk, or, when using a cloud storage provider such as Amazon S3, the profile photo's path within its "bucket".

### Defining the field

Next, let's attach the file field to our `UserRepository`. In this example, we will create the field and instruct it to store the underlying file on the `public` disk. This disk name should correspond to a disk name in your `filesystems` configuration file:

```php
use Binaryk\LaravelRestify\Fields\File;

public function fields(RestifyRequest $request)
{
return [
File::make('avatar')->disk('public')
];
}
```

### How Files Are Stored

When a file is uploaded using this field, Restify will use Laravel's [Filesystem integration](https://laravel.com/docs/filesystem) to store the file on the disk of your choosing with a randomly generated filename. Once the file is stored, Restify will store the relative path to the file in the file field's underlying database column.

To illustrate the default behavior of the `File` field, let's take a look at an equivalent route that would store the file in the same way:

```php
use Illuminate\Http\Request;

Route::post('/avatar', function (Request $request) {
$path = $request->avatar->store('/', 'public');

$request->user()->update([
'avatar' => $path,
]);
});
```

If you are using the `public` disk with the `local` driver, you should run the `php artisan storage:link` Artisan command to create a symbolic link from `public/storage` to `storage/app/public`. To learn more about file storage in Laravel, check out the [Laravel file storage documentation](https://laravel.com/docs/filesystem).

### Image

The `Image` field behaves exactly like the `File` field; however, it will instruct Restify to only accept mimetypes of type `image/*` for it:

```php
Image::make('avatar')->storeAs('avatar.jpg')
```

### Storing Metadata

In addition to storing the path to the file within the storage system, you may also instruct Restify to store the original client filename and its size (in bytes). You may accomplish this using the `storeOriginalName` and `storeSize` methods. Each of these methods accept the name of the column you would like to store the file information:

```php
Image::make('avatar')
->storeOriginalName('avatar_original')
->storeSize('avatar_size')
->storeAs('avatar.jpg')
```

The image above will store the file, with name `avatar.jpg` in the `avatar` column, the file original name into `avatar_original` column and file size in bytes under `avatar_size` column (only if these columns are fillable on your model).

### Pruning & Deletion

File fields are deletable by default, so considering the following field definition:

```php
File::make('avatar')
```
You have a request to delete the avatar of the user with the id 1:

```http request
DELETE: api/restify/users/1/field/avatar
```

You can override this behavior by using the `deletable` method:

```php
File::make('Photo')->disk('public')->deletable(false)
```

So now the field will do not be deletable anymore.

### Customizing File Storage

Previously we learned that, by default, Restify stores the file using the `store` method of the `Illuminate\Http\UploadedFile` class. However, you may fully customize this behavior based on your application's needs.

#### Customizing The Name / Path

If you only need to customize the name or path of the stored file on disk, you may use the `path` and `storeAs` methods of the `File` field:

```php
use Illuminate\Http\Request;

File::make('avatar')
->disk('s3')
->path($request->user()->id.'-attachments')
->storeAs(function (Request $request) {
return sha1($request->attachment->getClientOriginalName());
}),
```

#### Customizing The Entire Storage Process

However, if you would like to take **total** control over the file storage logic of a field, you may use the `store` method. The `store` method accepts a callable which receives the incoming HTTP request and the model instance associated with the request:

```php
use Illuminate\Http\Request;

File::make('avatar')
->store(function (Request $request, $model) {
return [
'attachment' => $request->attachment->store('/', 's3'),
'attachment_name' => $request->attachment->getClientOriginalName(),
'attachment_size' => $request->attachment->getSize(),
];
}),
```

As you can see in the example above, the `store` callback is returning an array of keys and values. These key / value pairs are mapped onto your model instance before it is saved to the database, allowing you to update one or many of the model's database columns after your file is stored.

#### Storeables

Of course, performing all of your file storage logic within a Closure can cause your resource to become bloated. For that reason, Restify allows you to pass an "Storable" class to the `store` method:

```php
File::make('avatar')->store(AvatarStore::class),
```

The storable class should be a simple PHP class and extends the `Binaryk\LaravelRestify\Repositories\Storable` contract:

```php
<?php

namespace Binaryk\LaravelRestify\Tests\Fixtures\User;

use Binaryk\LaravelRestify\Repositories\Storable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;

class AvatarStore implements Storable
{
public function handle(Request $request, Model $model, $attribute): array
{
return [
'avatar' => $request->file('avatar')->storeAs('/', 'avatar.jpg', 'customDisk')
];
}
}
```

:::tip Command
You can use the `php artisan restify:store AvatarStore` command to generate a store file.
:::

## BelongsTo

Expand Down
Loading