Services
Valravn has several services that each one has their own functionality.
Service contract
Service classes must extend Hans\Valravn\Services\Contracts\Service
class.
Available methods
cache
Cache method's result called on service instance.
1app( ExampleService::class )->cache()->calculatePopularExamples(); // result will store in cache
2app( ExampleService::class )->calculatePopularExamples(); // will not store anything in cache
cacheWhen
Sometimes you need to conditionally determine you want to use cache or not.
1app( ExampleService::class )->cacheWhen( user()->isNotAdmin() )->calculatePopularExamples();
Caching logic
This service helps up caching data and retrieve them on next calls. the logic of this service is a bit complicated but in the simplest way, it caches data and reset them for a fixed interval. let's assume we set a 15m interval. client send a request to retrieve some data at :00 o'clock. it's all about the minutes and seconds. that's why i said :00 o'clock. the requested data fetch and cache for next 15 minutes. if another request wants the cached data before :15 o'clock, the data will retrieve from cache. after :15 o'clock requests should receive fresh data for the first time. and cached data in second 15m will be valid until :29 o'clock.
CachingService
You can set your custom interval by using setInterval
method.
1app( PostRelationsService::class )->cache()->setInterval( 20 )->viewCategories();
Cache facade
This facade let you cache some data using same logic.
1use Hans\Valravn\Facades\Cache;
2
3Cache::store( 'unique_key', fn() => 10 / 12 );
FilteringService
The FilteringService
allows us to apply some logics on query builder instance
through api calls.
To apply requested filters on your queries, you should call applyFilters
method on your query builder instance. it's
recommended to call applyFilters
in your service layer.
Available filters
like_filter
Add a where like condition to the current query builder instance.
domain/api/blog/posts?like_filter[title]=something
order_filter
You can control order of returned items.
domain/api/blog/posts?order_filter[id]=asc
or set a descending order.
domain/api/blog/posts?order_filter[id]=desc
order_pivot_filter
If you are retrieving data using a many-to-many relationship and there is a pivot table, you can sort items based on a pivot column.
domain/api/blog/posts/1/categories?order_pivot_filter[order]=asc
and for reverse:
domain/api/blog/posts/1/categories?order_pivot_filter[order]=desc
where_filter
Using this filter, you can set one or more where condition on current builder instance.
domain/api/blog/posts?where_filter[id]=153,42
where_pivot_filter
When you are retrieving data from a relationship, you can set a where condition on a pivot column. let's assume we have a many-to-many relationship between posts and comments and there is a status column in our pivot table. this is how we can get accepted comments of a specific post.
domain/api/blog/posts/1/comments?where_pivot_filter[status]=accepted
where_relation_filter
This filter ables you to fetch posts that has a command with a specific title.
domain/api/blog/posts?where_relation_filter[comments->title]=something
where_relation_like_filter
It has the same functionality as where_relation_filter
but apply where like
condition.
domain/api/blog/posts?where_relation_like_filter[comments->title]=something
or_where_relation_filter
Mixing this filter with other filters, give us more flexibility to get the data
we really wanted. below example, shows how to get posts that has a title
like valravn
OR has a comment(s) that their title
is equal to something
.
domain/api/blog/posts?or_where_relation_filter[comments->title]=something&like_filter[title]=valravn
or_where_relation_like_filter
It's the same as or_where_relation_filter
but this filter add a where like
condition instead of where.
RoutingService
This service helps you to define your routes. the Hans\Valravn\Facades\Router
facade is here to make it easy to use this service.
Available methods
apiResource
Register CRUD routes for api. it has a same behaviour as Route::apiResource
of
laravel.
1use Hans\Valravn\Facades\Router;
2
3Router::apiResource( 'posts' , PostCrudController::class );
you can access the registered routes as usual in laravel.
resource
The same as apiResource
method but for MPA (Multi Page Application).
1use Hans\Valravn\Facades\Router;
2
3Router::resource( 'posts' , PostCrudController::class );
name
If there isn't any crud controller, you can just determine the name of the entity. next you will be able to register your related relations or whatever routes.
1use Hans\Valravn\Facades\Router;
2
3Router::name( 'posts' );
withBatchUpdate
This method determine you want to have a batch update route for your entity.
1use Hans\Valravn\Facades\Router;
2
3Router::apiResource( 'posts' , PostCrudController::class )->withBatchUpdate();
Created route's name is like posts.batch-update
.
relations
You can register your relationships routes using this method. first you need to pass the related controller class and then a closure. inside the closure, you can register your relationships.
1use Hans\Valravn\Facades\Router;
2
3Router::apiResource( 'posts' , PostCrudController::class )
4 ->withBatchUpdate()
5 ->relations(
6 PostRelationsController::class,
7 function( RelationsRegisterer $relations ) {
8 $relations->belongsTo( 'user' )->only(' view' );
9 $relations->belongsToMany( 'categories' )->except( 'attach' , 'detach' );
10 }
11 )
In PostRelationsController
you must have the viewUser
method for user
relationship and viewCategories
, updateCategories
for categories
relationship. also, the route's name should be {name}.{relation}.{action}
. for
example, for categories
relation, we have posts.categories.view
and posts.categories.update
.
actions
This method allows you to define some custom actions.
1use Hans\Valravn\Facades\Router;
2
3Router::apiResource( 'posts' , PostCrudController::class )
4 ->withBatchUpdate()
5 ->actions(
6 PostActionsController::class,
7 function( ActionsRegisterer $actions ) {
8 $actions->get( 'markAsReviewNeeded' );
9 $actions->withId()->get( 'makeDraft' );
10 $actions->withId()->parameters( 'user' )->get( 'setUserToReview' );
11 $actions->withId()->parameters( [ 'reviewer' => 'user' ] )->get( 'setUserToSpellCheck' );
12 }
13 )
First action generates domain/api/blog/posts/-actions/mark-as-review-needed
path and route that to markAsReviewNeeded
method on related controller.
Second one used withId
method that ended up to
register domain/api/blog/posts/-actions/{post}/make-draft
path which routes
to makeDraft
method on related controller. the makeDraft
method receives a
post model object.
In third example, we used parameters
method which adds more parameter(s) to
our path. if the parameter passes as a string like user
, it will
create domain/api/blog/posts/-actions/{post}/setUserToReview/{user}
path and
as always routes it to setUserToReview
method on related controller.
Fourth example passed a parameter as an array. this will generate the same route
but prefix parameter with array's key. the registered route should be
like domain/api/blog/posts/-actions/{post}/set-user-to-spell-check/reviewer/{user}
.
In the end, routes will be accessible through {name}.actions.{action_name}
naming pattern. for instance, the first action's name should
be posts.actions.mark-as-review-needed
.
gathering
This method helps when we want to gather a page requests and return all needed
data for a page using one request. everything is the same as actions
method
with several tiny difference.
1use Hans\Valravn\Facades\Router;
2
3Router::apiResource( 'posts' , PostCrudController::class )
4 ->withBatchUpdate()
5 ->gathering(
6 PostGatheringController::class,
7 function( GatheringRegisterer $gathering ) {
8 $gathering->get('posts');
9 $gathering->version(2)->withId()->get('post');
10 }
11 )
First example register domain/api/blog/posts/-gathering/v1/posts
path and
route it to postsV1
method on related controller. for example, you can return
posts with loaded first related category and user data all together.
Second one as you could guess,
register domain/api/blog/posts/-gathering/v2/{post}/post
path and route it
to postV2
method on related controller. you can return given post resource
with categories relationship data and maybe 5 first comment of the related post.
If you want to access gathering routes using route's name, you can
use {name}.gathering.{action_name}-v{version}
pattern. for example the first
gathering route's name is posts.gathering.posts-v1
.
There is an example of implementing a method on gathering controller. you can
use AnonymousResourceCollection
and pass your resource or resource collection
instances while wrapped with an array.
1use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
2
3class HomeGatheringController extends Controller {
4
5 public function version( ): AnonymousResourceCollection {
6 return AnonymousResourceCollection::make([
7 // your resource or resource collection instances go here
8 ]);
9 }
10
11}