Skip to content

#2 Build Your Controller

php anonymous edited this page Aug 23, 2023 · 30 revisions

CRUD-RF

A new term in programming interface applications is called CRUD-RF It will radically change your understanding by clarifying the criteria that you must follow while working to build your outputs in a flexible and fast manner

what does it mean (CRUD-RF) It is well known that the term CRUD It is one of the famous Laravel framework terms which means

  1. C - create
  2. R - Read
  3. U - Update
  4. D - Delete
  5. As for RF
  6. Restore
  7. ForceDelete To adopt the idea that you have two more additions This idea will be to extend the scope of your API

Well let's understand the idea These two features can be used if you want to recover or delete data using soft delete Great, it's easy Say we want to start building our controller

Through which we write the methods that output the data as needed, which is considered special API

It is as follows by default

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestApiController extends Controller
{
    public function index(){}
    public function show(){}
    public function update(){}
    public function destroy(){}
}

Well what if you just pass one thing that keeps you from filling all these methods

Here is the idea that the lynx came up with

through Lynx\Base\Api and set only the Model::class in protected $entity

use Lynx\Base\Api;
class TestApiController extends Api
{
     // Set your Model Here
     protected $entity = \App\Models\Test::class;
}

Watch with me that we replaced the controller and re-inherited with Lynx\Base\Api

We also have a Guest viewing mode for core values. But we will explain it later with policies

In less than a minute, you have complete control over your output without writing your methods

Route::apiResource('test',[TestApiController::class]); Full CRUD But what about RF Restore , ForceDelete

Well you can actually set this

RF

Looking at this method, you will find that it is specific and ready for use in Route::class Lynx\Base\Api@restore

Example :-

Route::post('test/restore/{id}',[TestApiController::class , 'restore']);

same situation with forceDelete Lynx\Base\Api@forceDelete

Route::delete('test/force/delete/{id}',[TestApiController::class , 'forceDelete']);

You can custom this routes as appropriate for you

query index,indexAny

in index and guest mode if you need custom your api Use this method to append your Query Method

example:

	/**
	 * can handel custom query when retrive data on index,indexGuest
	 * @param $entity model
	 * @return query by Model , Entity
	 */
	public function query($entity):Object {
		 return $entity->where('id', 1)->withTrashed();
 	}

Rules and Nice Name

Well, all this in one situation without the need to add many methods and many instructions, but there are two things left for us if you want to put the rules of addition and modification and nice names

It is known within the framework of Laravel that it is possible to specify or add FormRequest in store , update methods

But I have a slightly different view, is to shorten the code as much as possible

Suppose we have the following fields in our database table

title,desc,status,file

We wanted to define rules for these fields, what should we do?

see this example:-

class TestApiController extends Api {
     // Set your Model Here
     protected $entity = \App\Models\Test::class;
/**
 * @param $id integer if you want to use in update rules
 * @param string $type (store,update)
 * @return array by (store,update) type using $type variable
 */
public function rules($type, int $id = null):array{

	return $type == 'store'?
             // store Rules
             [
		'title'  => 'required|string',
		'desc'   => 'required|string',
		'status' => 'required|string',
		'file'   => 'required|file',
	]:
            // Update Rules
            [
		'title'  => 'required',
		'desc'   => 'required',
		'status' => 'required',
		'file'   => 'sometimes|nullable|file',
	];
}

/**
 * this method can set your attribute names with validation rules
 * @return array
 */
public function niceName():array{
	return [
		'title'  => __('main.title'),
		'status' => __('main.status'),
		'desc'   => __('main.desc'),
		'file'   => __('main.file'),
	];
}

}

I think you understand what you have to do now is to define the rules for the fields and put the names in the way that suits you

Append Data

But there is something I need to tell you so that you don't get confused

Every step you take in a quick build I try hard to make it smart and easy and see what comes with me in this step

Do you remember the fields we talked about earlier?

Among them is the field (file)

I think the moment has come that you will like it and be like magic

This field is supposed to be uploaded and its path is stored in the same field

For that purpose I have included great method that you can manually add some other fields to it without setting them in the rules

According to this method, Api@append it can include additional data, but please note that you specify the names of all fields

/**
 * this method append data when store or update data
 * @return array
 */
public function append():array{
	$data = [
	  'user_id' => auth()->user()->id,
	];
	$file = lynx()->uploadFile('file', 'test');
	if (!empty($file)) {
		$data['file'] = $file;
	}
	return $data;
}

Watch with me We have added two fields (user_id,file), one of them is not mentioned previously (user_id)

We added it here in our matrix to add data that does not come with the parameters coming from the user end of the front end or the mobile application

You can measure the rest of the upcoming operations in this way adding additional data with additional fields also excluded from the rules

So if you do not add this field in $fillable in your Model Lynx will tell you that you must add this field, and the process of adding or updating will stop sometimes or all the time

Lynx Helper

There is a ready-made help function that is used in several places with complete comfort. Upload files and outputs with assigning data to them. lynx helper function

lynx()

uploadFile Method

Another example of something new to your eyes that you saw now

$file = lynx()->uploadFile('file', 'test');
	if (!empty($file)) {
		$data['file'] = $file;
	}
lynx()->uploadFile($request_name = 'file',$path="testFolder")

lynx()->uploadFile() Lynx has a help function built into it several other functions, including the file upload function. All you have to tell it is the name of the parameter and the path you want to store the file in and it will return to you with the full path so that the path is stored inside the column in the table

⚠️ Do not forget this condition, it is very important in the event that you set the rule for this field as sometimes|nullable

In the event of the update, the value will return to null if you do not use the condition, so if the condition works during the update of the data, it will be the best solution for you

if (!empty($file)) {
    $data['file'] = $file;
    }

beforStore & afterStore

Storing data in a table is undoubtedly elegantly decorated But what if you have in the form something you want to prepare before or after storage Or you want to modify a value from one of the previously entered parameters Or you have a relationship with other tables that you want to append data to this Model Like Morph Or OneToMany or ManyToMany or Attach

Well here's the point

You can do something before adding and adding some other features using the . method

Let me give you an example Api@beforeStore

* this method use or append or change data before store
* @return array
*/
public function beforeStore(array $data):array{
	//$data['title'] = 'replace data';
	return $data;
}

Watch there is an array type variable that you prepared automatically to be able to modify the data before storing it, and before storage, you can put other functions as well, such as news mail or running something in the background or conditions and anything, however in the end you will be forced to return the array again

Let me give you an example Api@afterStore

/**
 * this method can use or append store data
 * @return array
 */
public function afterStore($entity):void {
	//dd($entity->id);
}

But after saving the data here, the situation is completely different That is, you can use the stored data for anything else Or you send after the additional data such as attach,detach and much more

Also, you will not be forced to resend the stored data again, as you see that the method does not require any data return, it is only a footer to the post-save or it is the end point anyway

beforeUpdate & afterUpdate

Here is the same situation as the addition, but in the update there is another difference Let me give an example anyway

/**
 * this method use or append or delete data beforeUpdate
 * @return array
 */
public function beforeUpdate($entity):void {
	if (!empty($data->file)) {
		\Storage::delete($data->file);
	}
}

Watch with me this example of before updating the data. You can delete a file or make conditions or any other commands in the background without requiring you to return anything data to the method again, so the situation is different, but in a fundamentally a bit deep

Well, what about if you want to change some data during the update?

Use my wits here this time and tell you that you can do this process by method Api@afterUpdate

/**
 * this method use or append data after Update
 * @return array
 */
public function afterUpdate($entity):void {
	//dd($entity->id);
}

I think you are satisfied now!

You can reformulate it as you see fit Also the process of attaching, detaching, and other relationships with other tables or other functions You can also use separate and attach before the update also means that you have complete control, intelligent and arranged in order that helps you to do things

beforeShow

There is no doubt that data mining is an essential thing I know you're thinking about how to include relationships, make some extra queries, or fetch more data during output

Let me give an example Api@beforeShow

/**
 * this method use or append data when Show data
 * @return array
 */
public function beforeShow($entity):Object {
 	return $entity->where('title', '=', null);
}

afterShow

There is no doubt that data mining is an essential thing I know you're thinking about how to include relationships or convert object to json resource with single, make some extra queries, or fetch more data during output

Let me give an example Api@afterShow

/**
 * this method use or append data when Show data
 * @return array
 */
public function afterShow($entity):Object {
  return new YourSingleJsonResource($entity);
}

See here I actually fetched the data before the show with full enablement to add more queries, add relationships, prepare data, or even conditions or any other functions

I think you will be impressed with what I show you

Because I don't depend on Model::find($id) Api@first query I think this will expand the scope of the query, especially if you are asking for a specific value for a user

beforeDestroy & afterDestroy

Don't worry, I've thought about the deletion process for you, whether before or after it

So you have two methods that you can use to do anything, whether mail news, background orders, or conditions as well

Let me give an example

/**
 * you can do something in this method before delete record
 * @param object $entity
 * @return void
 */
public function beforeDestroy($entity):void {
	if (!empty($entity->file)) {
		\Storage::delete($entity->file);
	}
}

As usual, you can do anything, conditions, jobs and many things

After deletion, this is an example

/**
 * you can do something in this method after delete record
 * @param object $entity
 * @return void
 */
public function afterDestroy($entity):void {
	// do something 
	// $entity->file
}

As before, you can do anything without being forced to return the data again to the method It's really genius

protected properties

First of all, what I will offer will save a lot of suffering and employ your needs according to your desire

These properties are very important

Let's show them one by one

//Set Your Model Or Entity If you are using nwidart module

protected $entity = \Modules\Test\Entities\Test::class ;

OR with Laravel normal way

protected $entity = \App\Models\Test::class ;

add specify key policy or if not added. lynx it can generate automatic key

protected $policy_key = 'test';

throw the Policy Class Here And let lynx to do everything using nwidart module

protected $policy = \Modules\Test\Policies\TestPolicy::class ;

OR with Laravel Policy

protected $policy = \App\Policies\TestPolicy::class ;

Change Your guard if you are using sanctum or other guard if you are not set lynx can use the default api guard or web

protected $guard = 'api';

You Can Show All Values in index by add new route with @indexAny Route::post('test','ApiController@indexAny');

protected $indexGuest = true;// this if user not logged-in

here you can show record id in store,update,delete data show or hide full json data when !

protected $FullJsonInStore   = false; // TRUE,FALSE
protected $FullJsonInUpdate  = false; // TRUE,FALSE
protected $FullJsonInDestroy = false; // TRUE,FALSE

Change paginate Status to use get method (paginate,get) in index,indexAny

protected $paginateIndex = true;

get Data withTrashed with restore and forceDelete methods

protected $withTrashed = true;

Define Custom Resources to index,indexAny to custom fields and columns

protected $resourcesJson = \Modules\Test\Transformers\TestResources::class ;

or By Laravel

protected $resourcesJson = \App\Http\Resources\TestResources::class ;

Spatie Query Builder Package

once you add this property you can use Spatie QueryBuilder Package with all functionality

   protected $spatieQueryBuilder = true; // when change value to false you can use ORM Model 

you must be install laravel querybuilder package made by spatie https://github.com/spatie/laravel-query-builder