Skip to main content

Repository Structure

Introduction#

In this section, we'll discover the structure of a generated repository file.

Note

This structure is a bias one regardless the database engine used in the project.

A typical repository file structure#

The following example illustraes the repository structure regardless the database engine type.

Please note that this structure is used as an easier alternative for create update list methods.

UsersRepository.php
<?php
namespace App\Modules\Users\Repositories;
use App\Modules\Users\{
Models\User as Model,
Resources\UserResource as Resource,
Filters\UsersFilter as Filter
};
use HZ\Illuminate\Mongez\{
Contracts\Repositories\RepositoryInterface,
Managers\Database\MongoDB\RepositoryManager
};
class UsersRepository extends RepositoryManager implements RepositoryInterface
{
/**
* Repository Name
*
* @const string
*/
const NAME = 'users';
/**
* Model class name
*
* @const string
*/
const MODEL = Model::class;
/**
* Resource class name
*
* @const string
*/
const RESOURCE = Resource::class;
/**
* Set the columns of the data that will be auto filled in the model
* Please use the following data types for more convenient data types
*
* @const array
*/
const DATA = [];
/**
* Set columns list of string values.
*
* @cont array
*/
const STRING_DATA = ['name', 'email', 'password'];
/**
* Set columns list of integers values.
*
* @cont array
*/
const INTEGER_DATA = ['mobile_number'];
/**
* Set columns list of float values.
*
* @cont array
*/
const FLOAT_DATA = ['salary'];
/**
* Set columns of booleans data type.
*
* @cont array
*/
const BOOLEAN_DATA = ['newsletter_subscribed'];
/**
* Localized data
*
* @const array
*/
const LOCALIZED_DATA = [];
/**
* Auto save uploads in this list
*
* If it's an indexed array, in that case the request key will be as database column name
* If it's associated array, the key will be request key and the value will be the database column name
*
* It can be passed as well as an array of options, current options schema:
* [
* 'input' => 'string', // the input that will be read from the request files, if not present, it will be same as $column key
* 'column' => 'string', // if not present, it will be same as $key key
* 'clearable' => 'bool', // if set to true, the column value will be set to empty if there is no file to be uploaded
* 'arrayable' => 'bool', // if set to true, it will be stored as an array, if set to null it auto determined
* ]
*
* @const array
*/
const UPLOADS = ['avatar'];
/**
* Geo Location data
*
* @const array
*/
const LOCATION_DATA = [];
/**
* Set columns list of date values.
*
* @cont array
*/
const DATE_DATA = ['birth_date'];
/**
* Auto fill the following columns as arrays directly from the request
* It will encoded and stored as `JSON` format,
* it will be also auto decoded on any database retrieval either from `list` or `get` methods
*
* @const array
*/
const ARRAYBLE_DATA = [];
/**
* Add the column if and only if the value is passed in the request, if set to true, it will ignore all changing all columns that is not in the request data.
*
* @cont array
*/
const WHEN_AVAILABLE_DATA = [];
/**
* Determine wether to use pagination in the `list` method
* if set null, it will depend on pagination configurations
*
* @const bool
*/
const PAGINATE = null;
/**
* Number of items per page in pagination
* If set to null, then it will taken from pagination configurations
*
* @const int|null
*/
const ITEMS_PER_PAGE = null;
/**
* Set all filter class you will use in this module
*
* @const array
*/
const FILTERS = [
Filter::class
];
/**
* Filter by columns used with `list` method only
*
* @const array
*/
const FILTER_BY = [
'int' => ['id'],
'like' => [
'name', 'email', 'mobile_number'
]
];
/**
* Set any extra data or columns that need more customizations
* Please note this method is triggered on create or update call
*
* @param mixed $model
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function setData($model, $request)
{
//
}
/**
* Do any extra filtration here
*
* @return void
*/
protected function filter()
{
//
}
}

Let's go in depth with the repository file

Repository name#

/**
* Repository Name
*
* @const string
*/
const NAME = 'users';

Here we defined the repository alias name that is used in the config/mongez.php file in repositories section.

Repository Main Model#

/**
* Model class name
*
* @const string
*/
const MODEL = Model::class;

As a repository, it handles only one model for data insertion/update/delete or fetching, you can however work with more models in the declared methods.

In our example, it will be App\Modules\Users\Models\User model will be used here.

tip

The repository generator makes a class alias to model, filter or resource class at the class namespace declaration block for better usage.

Repository Main Resource#

/**
* Resource class name
*
* @const string
*/
const RESOURCE = Resource::class;

Declares the main resource class that will be used in the Wrapping Methods in data fetching.

Storing/Updating Generic data#

/**
* Set the columns of the data that will be auto filled in the model
* Please use the following data types for more convenient data types
*
* @const array
*/
const DATA = [];

Starting from this section, we'll start distributing our data in constants for more convenient way of data insertion/update.

This DATA constant accepts any type of data that can be stored directly without any manipulation or handling.

Not recommended

This constant is not recommended to be used unless there are some generic data that has no certain type.

Auto password encryption

If the constant array contains password column, it will be auto encrypted using the bcrypt function.

Storing/Updating String data#

/**
* Set columns list of string values.
*
* @cont array
*/
const STRING_DATA = ['name', 'email', 'password'];

Cast name, email, password inputs as string value in the create/update methods.

Auto password encryption

If the constant array contains password column, it will be auto encrypted using the bcrypt function.

Storing/Updating integer data#

/**
* Set columns list of integers values.
*
* @cont array
*/
const INTEGER_DATA = ['mobile_number'];

Cast mobile_number input as interger value in the create/update methods.

Storing/Updating float Data#

/**
* Set columns list of float values.
*
* @cont array
*/
const FLOAT_DATA = ['salary'];

Cast salary input as float value in the create/update methods.

Storing/Updating boolean data#

/**
* Set columns of booleans data type.
*
* @cont array
*/
const BOOLEAN_DATA = ['newsletter_subscribed'];

Cast newsletter_subscribed input as boolean value in the create/update methods.

info

If the boolean input is sent in he request as false in string it will be auto casted into false as boolean value.

Storing/Updating Localized Data#

/**
* Localized data
*
* @const array
*/
const LOCALIZED_DATA = [];

This part of data is handled differently in each database engine, please refer to it in MYSQL Repository and MongoDB Repository

Storing/Updating Uploads#

/**
* Auto save uploads in this list
*
* If it's an indexed array, in that case the request key will be as database column name
* If it's associated array, the key will be request key and the value will be the database column name
*
* It can be passed as well as an array of options, current options schema:
* [
* 'input' => 'string', // the input that will be read from the request files, if not present, it will be same as $column key
* 'column' => 'string', // if not present, it will be same as $key key
* 'clearable' => 'bool', // if set to true, the column value will be set to empty if there is no file to be uploaded
* 'arrayable' => 'bool', // if set to true, it will be stored as an array, if set to null it auto determined
* ]
*
* @const array
*/
const UPLOADS = ['avatar'];

This constant handles data uploading and storing in database.

Uploading files system has simple to advanced features, let's see it step by step.

Uploading single/multiple files#

UPLOADS constant accepts single file upload and multiple files upload, simply put the file column name and the managers will handle the two cases accordingly

Storing multiple files

Based on your database engine the multiple uploads database storage is handled differently, in MongoDB the uploads are stored as an array, while MYSQL stored data as json.

tip

This can be overriden by defining SERIALIZE_MULTIPLE_UPLOADS constant with a boolean value in your desired repositorty.

In MYSQL, the default value is true, while in MongoDB, the default value is false.

/**
* If set to true, the multiple uploads column paths will be json encoded while storing it in database.
*
* @const bool
*/
const SERIALIZE_MULTIPLE_UPLOADS = false;

Ignoreable by default#

Any uploaded column is Ignoreable if there is no files uploaded in the update request.

If the model is being updated and there was a file uploaded in the creating step, for example user's avatar image is uploaded when user has created his/her accoumt, if user wants to update his/her profile and there is no avatar image is passed to the server, the avatar image will be remained the same old one.

Configurable options for each single column#

If you want to override default behavior for the previous options, you can override it by passing an array of options instead of the column name as follows:

/**
* Auto save uploads in this list
*
* If it's an indexed array, in that case the request key will be as database column name
* If it's associated array, the key will be request key and the value will be the database column name
*
* It can be passed as well as an array of options, current options schema:
* [
* 'input' => 'string', // the input that will be read from the request files, if not present, it will be same as $column key
* 'column' => 'string', // if not present, it will be same as $key key
* 'clearable' => 'bool', // if set to true, the column value will be set to empty if there is no file to be uploaded
* 'arrayable' => 'bool', // if set to true, it will be stored as an array, if set to null it auto determined
* ]
*
* @const array
*/
const UPLOADS = [[
'input' => 'coverPicture', // the request input name
'column' => 'cover', // the column name in database
'clearable' => true, // if there is no converPircture file in the request, the `cover` column will be cleared
'arrayable' => false, // single file only
]];

Storing/Updating geo location data#

/**
* Geo Location data
*
* @const array
*/
const LOCATION_DATA = ['location'];

Store the location inputs as geo location data in the database.

This is handled differently in MYSQL and MongoDB Databases.

Storing/Updating date data#

/**
* Set columns list of date values.
*
* @cont array
*/
const DATE_DATA = ['birth_date'];

Store birth_date in database as date, can be used for filtration using Carbon.

Declaring $dates property in the model

Any column defined in DATE_DATA constant must be defined in the $dates property in its corresponding model, otherwise searching by date won't work properly.

App\Modules\Users\Models\User
<?php
namespace App\Modules\Users\Models;
use HZ\Illuminate\Mongez\Managers\Database\MYSQL\Model;
class User extends Model
{
/**
* {@inheritDoc}
*/
protected $dates = ['birth_date'];
}

Storing/Updating arrayable data#

/**
* Auto fill the following columns as arrays directly from the request
* It will encoded and stored as `JSON` format,
* it will be also auto decoded on any database retrieval either from `list` or `get` methods
*
* @const array
*/
const ARRAYBLE_DATA = [];

This array stores the data as json in database, can be usful for bulk data such as permissions list.

info

For MYSQL database, the data is stored as json, in MongoDB it is stored as sent, array or object.

When available data and ignoring values#

/**
* Add the column if and only if the value is passed in the request, if set to true, it will ignore all changing all columns that is not in the request data.
*
* @cont array
*/
const WHEN_AVAILABLE_DATA = [];

In all previous storage constants, if the column's value is not sent in the create or update method, the value will be cleared, unless the column is declared in the WHEN_AVAILABLE_DATA.

the UPLOADS constant is the only constant ignoring empty values and does not clear the value.

Let's see an example for its usage:

UsersRepository
/**
* Set columns list of string values.
*
* @cont array
*/
const STRING_DATA = ['name', 'email'];
/**
* Add the column if and only if the value is passed in the request, if set to true, it will ignore all changing all columns that is not in the request data.
*
* @cont array
*/
const WHEN_AVAILABLE_DATA = ['name'];
UsersController
/**
* Create new user
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$user = $this->repository->create([
'name' => 'Hasan',
'email' => 'hassanzohdy@gmail.com'
]);
}

The user data will be name as Hasan and email as hassanzohdy@gmail.com.

{
"name": "Hasan",
"email": "hassanzohdy@gmail.com"
}

Now let's update the user info

UsersController
/**
* Update user's info
*
* @param int $id
* @param Request $request
* @return Response
*/
public function update($id, Request $request)
{
$user = $this->repository->update($id, [
'email' => 'john@smith.com'
]);
}

Now the user data will be name as Hasan and email as john@smith.com.

{
"name": "Hasan",
"email": "john@smith.com"
}

But what the email is not sent in the update process?

UsersController
/**
* Update user's info
*
* @param int $id
* @param Request $request
* @return Response
*/
public function update($id, Request $request)
{
$user = $this->repository->update($id, [
'name' => 'Mohammad'
]);
}

As the email is not ignorabe, it's value will be cleared, so the user data now will be name as Ali and email as empty string.

{
"name": "Mohammad",
"email": ""
}

But if no data is sent at all?

UsersController
/**
* Update user's info
*
* @param int $id
* @param Request $request
* @return Response
*/
public function update($id, Request $request)
{
$user = $this->repository->update($id, [
]);
}

The same applies, All columns will be checked if it is in the WHEN_AVAILABLE_DATA constant, in our example only the name is listed there.

So the user's data will be as follows:

{
"name": "Mohammad",
"email": ""
}

Setting WHEN_AVAILABLE_DATA to true#

If the WHEN_AVAILABLE_DATA is set to true, any column that has no value will be kept with its current value.

UsersRepository
/**
* Set columns list of string values.
*
* @cont array
*/
const STRING_DATA = ['name', 'email'];
/**
* Add the column if and only if the value is passed in the request, if set to true, it will ignore all changing all columns that is not in the request data.
*
* @cont array
*/
const WHEN_AVAILABLE_DATA = true;
UsersController
/**
* Create new user
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$user = $this->repository->create([
'name' => 'Hasan',
'email' => 'hassanzohdy@gmail.com'
]);
}

User data will be:

{
"name": "Hasan",
"email": "hassanzohdy@gmail.com"
}
UsersController
/**
* Update user's info
*
* @param int $id
* @param Request $request
* @return Response
*/
public function update($id, Request $request)
{
$user = $this->repository->update($id, []);
}

User data will remain the same as no values are passed to any column.

{
"name": "Hasan",
"email": "hassanzohdy@gmail.com"
}