Nishchay Framework v1.1 announcement

Tags:

Here we are announcing upcoming version of nishchay framework. We have updated framework as per user feedback and also added many features to make development even much faster.

We will first launch beta version and then release candidate version will be launched. Beta and release candidate phase will run 15 days each. During this duration, multiple versions of beta and release candidate will be keep coming. Please do not use beta and release candidate versions in live environment, Once stable version is launched you can use it in live environment

Dates will be announced soon, please keep visiting blog section

New Features
  1. Route pattern
  2. Route visibility
  3. Stage route
  4. Abstract route
  5. Container
  6. Prototype
  7. Maintenance mode - whitelist IPs
  8. Entity Property - Predefined validation
  9. Entity records - Added multiple methods
  10. Depends validation
  11. Console command - Generator
Route Pattern

Route pattern works on method declared in controller and its parameters (You do not have define route annotation on method). Nishchay will have few predefined route pattern and developer can define their own pattern.

Route pattern iterates over each method and looks for its parameter, based on method and its parameter route path are created. This makes @Route annotation to be optional if controller is following route pattern. For the predefined route pattern, if controller method has defined @Route annotation on method will override route pattern.

To support this feature pattern parameter has been added to @Routing annotation of controller class.

Action

Pattern name: action This pattern prepares route whose method name starts with action. Controller method which does not starts with action are ignored for the pattern. See below code:

/**
* @Controller
* @Routing(prefix=todo,pattern=action)
*/
class ToDoController {
    public function actionIndex() {
    }

    public function actionList() {
    }

    public function actionView(){
    }

    public function edit(){
    }
}

Above controller follows action pattern as defined in @Routing annotation. For the above controller below route path will be created:

  1. todo
  2. todo/list
  3. todo/view

Method edit won't be considered as route method as it does not starts with action. For the actionIndex, it will be considered as @Route(path='/')

Action method

Pattern name: actionMethod

action method pattern is an improved pattern of action which prepares route along with HTTP method. Method which have action{HTTP_METHODS}{PathName} are considered as route. Here HTTP_METHOD is optional.

Creating POST route:

public function actionPostAdd(){
}

Method without HTTP will be treated with all supported HTTP methods.

Creating route with multiple HTTP methods

public function actionPostPutManage(){
}
Action method parameter

Pattern name: actionMethodParameter

Action method parameter is again improved pattern of action method which creates placeholder segment in route path from method parameter. Supported value for placeholder depends on parameter type. Only parameter which have scaler parameter type are considered as route placeholder segment.

This methods iterates over each method parameter, it stops when parameter is non scalar type. Below are supported scalar types:

  1. String
  2. Int
  3. Bool
  4. Array

Example 1:

public function actionPostUser(int $userId) {
}

Created route for above method will be user/{userId} This will be post route and userId must be integer.

Example 2: Multiple segments

public function actionUser(int $userId, string $action) {
}

Creates route: user/{userId}/{action} where userId must be integer and action can be any valid string.

Example 3: Optional segment Optional segment cna be created by either by using nullable type or parameter with default value.

Both of below code creates same route:

public function actionUser(int $userId, ?string $action) {
}
public function actionUser(int $userId, string $action = 'view') {
}

Created route: user/{userId}/?{action}. When you define parameter with nullable type then default value be null.

CRUD

Pattern name: crud. This allow creating crud route based on method name only. When method name exactly matches below supported method name then it creates route associated with it.

Method Name Route HTTP Method
index / GET
create / POST
fetch /{id} GET
update /{id} PUT
delete /{id} DELETE

For this pattern, method with name other than above are ignored. But still developer can define route annotation and create route within this controller.

Route Visibility

Route visibility will allow routes belonged to configured scope to be visible based on following things:

  1. Time range
  2. User agent
  3. List of IPs
  4. Callback

This will allows to create list of route which will be belongs to specific scope, then we can define visibility for given scope.

When application receives request and requested route is belongs to scope which has visibility defined in settings then it will visible based on following conditions:

Time range

Route will be visible for certain time, this range can defined as follows:

  1. Time greater than: will be visible after given time
  2. Time less than: will be visible till time is reached.
  3. Time range: will be visible for given time or date range.
User agent

Route will be for given list of user agents. Developer can declare any number user agents.

IPs

Route will be visible for given list of IPs

Callback

Route will be visible if given callback returns true.

Stage route

This will allow route to be available for single multiple application stage(local or stage) only. Suppose if we have defined route for test stage then it will be available for application stage test only. Stage routes are not available for live application stage.

Example

/**
* @Route(path='test',stage=local)
*/
public function test(){
}

Above will create route test which will be available for application stage local only.

Abstract Route

Now route annotation can also be defined on abstract method which will make it behave as static route. Static route response type must be view.

To make which view route should return, view parameter has been added to @Response annotation. This parameter will be applicable only abstract route.

Example

abstract class StaticController {

    /**
    * @Route(path='aboutUs', view='static/view')
    */
    abstract public function aboutUs();
}

When route does not define view in @Response annotation then route path will be considered as view path.

Example 2

abstract class StaticController {

    /**
    * @Route(path='aboutUs')
    */
    abstract public function aboutUs();
}

As in above case @Response does not have defined view parameter in it, in this case route path aboutUs will taken view path and nishchay processor will locate view with name aboutUs.

One more setting abstractViewPath added response.php setting, which will be used for prefix for the view path (Applicable only when @Response annotation does not define view parameter).

As shown in above example, view path taken as aboutUs which can be prefix by setting abstractViewPath = 'static' which will then make view path static/aboutUs.

interface

We can also create interface for static routes. All method within interface which have @Route annotation on will be considered as abstract route

Route pattern

Abstract route also works with route pattern.

note
  1. Route path of abstract route must not contain placeholder segment.
  2. Response type of abstract must be view.
  3. When controller class is abstract then it must contain only abstract route.
Container

Container as the name suggests, it will be used to contain lot of things together. Container is always singleton meaning wherever you use you will get same instance of container.

Containers should return instance of any class or class name. When container method returns class name, Nishchay container processor will create object of returned class name and give it back to you.

Example


use Application\Entities\User; use Nishchay\Session\ReadLimit; /** * @Container */ class AccountContainer { public function getUser() { return User::class; } public function getReadLimit() { return new ReadLimit(3); } }
Using above container
$userEntity = Nishchay::getContainer(AccountContainer::class)->getUser();

Calling Nishchay::getContainer(AccountContainer::class) returns instance of container. Calling getUser returns instance of EntityManger for the User class, because returned class is an entity. Every time we call getUser it will return same instance.

As you can see in getReadLimit always returns new instance of ReadLimit session, but it does not happen what you expect when using container. Below call will always returns same instance even though getReadLimit returns new instance.

Nishchay::getContainer(AccountContainer::class)->getReadLimit()
New instance

To fetch new instance every time, pass true as parameter to container method. Below code will always returns new instance.

$userEntity = Nishchay::getContainer(AccountContainer::class)->getUser(true);
Container method parameter

When container method has parameter, it shifted one position right. This is because first parameter of container is used for fetching new or same instance. To demonstrate this use case, we will be modifying getReadLimit method.

public function getReadLimit(int $limit) {
        return new ReadLimit();
    }

Now above container method can be used as

Nishchay::getContainer(AccountContainer::class)->getReadLimit(false, 3)

If you call multiple time getReadLimit method, you do not have pass parameter every time. You can omit parameter after first time it get called.

Parameter auto resolve

When container method returns class name then nishchay container processor first resolves parameter of returned class and then it creates instance of returned class by passing resolved parameter.

There's many way nishchay can resolve constructor parameter, you will find detailed explanation of how parameter are resolved in container documentation. Link to container documentation will updated once beta phase is finished.

Prototype

Prototype is predefined implementation which also allows customization. It comes with validation of requests, assigning request parameter to entity properties and then it saves.

Following prototypes have been added:

  1. Login
  2. Register
  3. Crud
Login

Login prototype makes user login into system. Login prototype is part of parent prototype Account.

Example

/**
 * Authenticates user and returns token to access all service which requires token.
 * 
 * @Service(token=false)
 * @Route(see=true,type=POST)
 * @Response(type=JSON)
 */
public function login(AccountPrototype $accountPrototype)
{
        $response = $accountPrototype->getLogin(User::class)
                        ->setForm(Login::class)
                        ->execute();

        return $response->isSuccess() ? $response->getAccessToken() : $response->getErrors();
}

When we fetch login prototype, we must pass entity class of user from which user detail need to be fetched. We can optionally set Form so that first request is validated using form. If form returns error then it responds with error.

Login prototype can do following things

  1. Validate request parameter if form has been set.
  2. Checks user is active and verified.
  3. Password verification, you can set callback to verify password as per your implementation
  4. Writes login data to session(Disabled by default, it can be enabled)
  5. Generates oauth2 token
  6. isSuccess can be used to find out login success or not
Register prototype

Register prototype also does things which are mentioned in above login prototype. It first makes user register into application and then makes user login into an application.

Crud prototype

CRUD prototype comes with following implementation

  1. Fetch records (Pagination based on request parameter, pagination can be disabled)
  2. Fetch single record
  3. Insert record
  4. Update record
  5. Delete record
Maintenance mode - white listed IPs

To allow access to application even in maintenance from list of IPs, white listing IPs has been added maintenance configurations. To achieve this following setting has been added to maintenance.php setting:

'exception' => [
        'ip' => [
                    '127.0.0.1'
            ]
    ]
Entity Property - Predefined validation

Entity property will be able use predefined validation which we use in Form or Validation class. Entity property can have following validation:

  1. Mixed
  2. Date
  3. String
  4. Number

Example

    /**
     * @Validation(rule='email')
     * @DataType(type=string, length=50, required=true,encrypt=true)
     */
    public $email;

    /**
     * @Validation(rule='string:min',parameter=3)
     * @Validation(rule='string:max',parameter=20)
     * @DataType(type=string, length=250, required=true,encrypt=true)
     */
    public $firstName;

Above will make email to have only valid email address and firstName character length should be between 3 and 20.

We can add any number of validation to property.

Entity records - Added multiple methods

When we fetch list of records using EntityManager or EntityQuery, it returns instance DateIterator which holds all records which are fetched. Following methods are added to DateIterator

  1. divide
  2. column
  3. unique
  4. sum
  5. average
  6. group
  7. combine
divide

When we fetch records form multiple entities using entity query, it returns as follows:

[
    {
        "user" : {},
        "department": {}
    },
    {
        "user" : {},
        "department": {}
    },
    {
        "user" : {},
        "department": {}
    }
]

If we call divide method on returned records then output will be:

{
    "user": [
        {},{},{}
    ],
    "department": [
        {},{},{}
    ]
}
column

Returns value of given property name as an array. If want to fetch nested property then it should be separated by dot.

$records->column('departmentId');

Returns all departmentIds from records of each row. There can be duplicated record if it exists.

unique

This works similar to column method except this method returns unique values of given column.

sum

Returns sum of given property. To find sum of nested property it should be separated by dot.

average

Returns average of given property.

group

Groups records based on value of given property name.

combine

Combine two different records based on property value which are matched.

Console command
Alias

Added alias for main command which are listed below:

Command Alias
route r
controller c
event ev
entity e
form (new command) f
prototype (new command) p

php nishchay r is similar to php nishchay route.

Generate entity - interactive command

Console command now will allow creating new entity along with table in database. This command will ask for entity name and all properties which needed to be created in entity class with their data type.

php nishchay entity -generate -new

Execute above command will ask for entity name, then first property will be considered as identity of property and its data type will be taken as int by default. Then it will keep asking for property.

To stop creating property press q .

Once entity is created it will ask whether you want to create table in database.

Generate entity - form single or all table

Console command now allows creating entity from database table. It will now allow creating entity from single table or all tables within database.

php nishchay entity -generate -table "TableName" {?connectionName}

Here connectionName is optional, omitting it will use default database connection.

Creating entities of all tables in database

php nishchay entity -generate -db {?connectionName}

Here connectionName is optional, omitting it will use default database connection.

Generate form class from entity

We are adding one more command form which will allow creating form class from entity class.

php nishchay form -generate -entity "{ClassName}"
Generate CRUD prototype

Generating prototype using console generates following things

  1. Creates entity
  2. Creates table (If prototype not generated from table)
  3. Creates form for validation of requests
  4. Creates CRUD routes which comes with following implementation 1. List to fetch all records(with pagination) 2. Fetch record 3. Insert record 4. Update record 5. Delete record

Prototype can generated by using interactive command called -new or it can be created from table. When prototype is created using interactive command then it will ask for creating table in database.

Other improvements
  1. Response type blank was considered as null, now it will result in an exception.
  2. Parameter defined in route method will be resolved as follows(based on parameter name):
    1. If parameter name found in request segment and value from segment assigned to parameter.
    2. If there's request file name same as parameter name then request file will be assigned to parameter.
    3. If parameter name exists in POST request parameter and then this value will be assigned to method parameter.
    4. If parameter name exists in GET request parameter and then this value will be assigned to method parameter.
    5. If none of above matches and request paramter type hint is allowing NULL then null will be returned otherwise it will result in an exception.
  3. @Namedscope now throw exception for the empty scope name.
  4. Added placeholder type int as an alias to number.
  5. Route parameter name see now doesn't allow value other than boolean, same validation also added for incoming parameter.
  6. Added pattern parameter to @Routing annotation for the support of route pattern.
  7. Settings now allows assigning closure.
  8. @Entity without any paramter will be discarded, as this annotation accepts parameter it should be defined with parameter only.
  9. Before event for route will be called before instance of controller is created, till now it was being called after instance of controller has been created.