tailflow / laravel-orion Goto Github PK
View Code? Open in Web Editor NEWThe simplest way to create REST API with Laravel
Home Page: https://orion.tailflow.org
License: MIT License
The simplest way to create REST API with Laravel
Home Page: https://orion.tailflow.org
License: MIT License
In some cases you don't want to use pagination, please add a concern to avoid/disable using pagination.
Such as
<?php
namespace App\Http\Controllers\Api;
use App\Models\Post;
use Orion\Concerns\DisablePagination;
use Orion\Http\Controllers\Controller;
class PostController extends Controller
{
use DisablePagination;
protected $model = Post::class;
}
Declaration of App\\Http\\Controllers\\Orion\\AdminAuthorisedIpsController::performStore(Illuminate\\Http\\Request $request, App\\Models\\AdminAuthorisedIp $adminAuthorisedIp, array $attributes): void should be compatible with Orion\\Http\\Controllers\\Controller::performStore(Orion\\Http\\Requests\\Request $request, Illuminate\\Database\\Eloquent\\Model $entity, array $attributes): void"
is it possible to make use of slug istead of id?
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName()
{
return 'slug';
}
so far using slug gave me SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for type bigint:
error
The store
and update
methods rely solely on $model->getFillable()
However this returns empty when the models use $guarded
instead of $fillable
We should hence gracefully fallback to $model->getGuarded()
in such situations
Would love to be able to include
nested relations.
Something like this:
protected function includes(): array
{
return ['business.manager'];
}
would be able to save a few calls to the API!
Thanks a million for this package, I absolutely love it. So beautifully written ๐
Hello guys,
I have a problem with the belongsToManyResources
routes, I need the bidirectional mapping to work together.
Orion::belongsToManyResource('users', 'customers', \App\Http\Controllers\API\UserCustomerController::class);
Orion::belongsToManyResource('customers', 'users', \App\Http\Controllers\API\CustomerUserController::class);
When the attach method of endpoint /users/{user}/customers/attach
is called, the record is inserted correctly. However when the endpoint /customers/{customer}/users/attach
method is called orion tries to insert a new user, for some reason it does not have the same behavior as the first endpoint.
The mappings are correct according to the laravel documentation. The table is also mapped in both relationships.
Can someone help me?
Thanks
How would we go about implementing null filters
{
"filters": [{
"field": "created_at",
"operator": ">=",
"value": "2021-02-01"
},
{
"field": "created_at",
"operator": "<=",
"value": "2021-02-28"
},
{
"field": "category_id",
"operator": "=",
"value": null
}
]
}
This throws the following error
"The filters.2.value field is required when filters is present."
I have a search query with filter and sort applied as shown below. This endpoint was working fine before and I started getting an empty response even though there are valid records in the DB. Even the total count in the response was correct.
This issue was appearing only when using the sort filter. I updated one of the record and I started getting the results again. I'm not able to reproduce this issue.
What might be the issue here?
Add the following trait on your controller, It will override the default API guard.
trait UserResolverTrait
{
public function resolveUser(): ?\Illuminate\Contracts\Auth\Authenticatable
{
return Auth::guard('web')->user();
}
}
Hello,
Please,could provide us an example how to upload images using spatie media package ?
NB: I'm using Nuxt js.
Thanks
I have follwed the documentation however when I visit api.consultation-category.show, supplying the id. returns status code 422 axios.get('api/consultation-category/' + cat_id)
.then((response)=>{
console.log(response)
})
controller
I placed my Api controllers inside a folder called Api
I want to modify the model query in a controller before a request is executed. This is required if I want to filter the data and show only owned models by a user in the index method,
Currently, I'm overriding newModelQuery in the controller to achieve the above
//in PostController.php
public function newModelQuery(): Builder
{
$query = $this->getModel()::query();
if(auth()->user()->hasRole('user')){
$query = $query->where('user_id', auth()->user()->id);
}
return $query;
}
is there any better way to do this?
Can the hook itself pass the query builder as shown below?
protected function beforeIndex(Request $request, $query)
{
if(auth()->user()->hasRole('user')){
$query = $query->where('user_id', auth()->user()->id);
}
}
This may be something more suited to userland, yet I thought it was worth asking!
Sometimes, we want to include attributes in our request. Laravel allows us to automatically append these attributes with appends
protected $appends = ['is_admin'];
However, often we only want those attributes on occassion. So My feature request is this.
Allow the developer to have an appends
array on the Controller, similar to how we currently use includes
protected function appends() : array
{
return ['is_admin'];
}
Then we can use the following query to only append what we need:
(GET) https://myapp.com/api/users?appends=is_admin
Thoughts? ๐
I want to listen to pivot model events in an Observer. Currently, the Pivot model observer is not triggered when updating pivot fields using many-to-many relationships.
Hello, I'm new to Laravel Orion.
I'm trying to get the forum index or a specific forum model by id, but I'm struggling for hours now because he's not accepting or ignoring my policy.
I'm getting the error "This action is unauthorized."
When adding the Orion\Concerns\DisableAuthorization
trait it works fine.
AuthServiceProvider.php
<?php
namespace App\Providers;
use App\Models\Forum;
use App\Policies\ForumPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
//'App\Models\Forum' => 'App\Policies\ForumPolicy', <-- This didn't work
Forum::class => ForumPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
// This didn't work
// Gate::guessPolicyNamesUsing(function ($modelClass) {
// return 'App\\Policies\\' . class_basename($modelClass) . 'Policy';
// });
}
}
I have tried php artisan config:clear
, php artisan cache:clear
and composer dump
to make sure he's using the right policies.
ForumController.php
<?php
namespace App\Http\Controllers\Api;
use App\Models\Forum;
use Orion\Http\Controllers\Controller;
class ForumController extends Controller
{
protected $model = Forum::class;
}
Forum.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Forum extends Model
{
use HasFactory;
}
ForumPolicy.php
<?php
namespace App\Policies;
use App\Models\Forum;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class ForumPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* @param User $user
* @return mixed
*/
public function viewAny(User $user): bool
{
return true;
}
/**
* Determine whether the user can view the model.
*
* @param User $user
* @param Forum $forum
* @return mixed
*/
public function view(User $user, Forum $forum): bool
{
return true;
}
/**
* Determine whether the user can create models.
*
* @param User $user
* @return mixed
*/
public function create(User $user): bool
{
return true;
}
/**
* Determine whether the user can update the model.
*
* @param User $user
* @param Forum $forum
* @return mixed
*/
public function update(User $user, Forum $forum): bool
{
return true;
}
/**
* Determine whether the user can delete the model.
*
* @param User $user
* @param Forum $forum
* @return mixed
*/
public function delete(User $user, Forum $forum): bool
{
return true;
}
/**
* Determine whether the user can restore the model.
*
* @param User $user
* @param Forum $forum
* @return mixed
*/
public function restore(User $user, Forum $forum): bool
{
return true;
}
/**
* Determine whether the user can permanently delete the model.
*
* @param User $user
* @param Forum $forum
* @return mixed
*/
public function forceDelete(User $user, Forum $forum): bool
{
return false;
}
}
api.php
<?php
use App\Http\Controllers\Api\ForumController;
use Illuminate\Support\Facades\Route;
use Orion\Facades\Orion;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group(['as' => 'api.'], function () {
Orion::resource('forums', ForumController::class)->withSoftDeletes()->withoutBatch();
});
What am I doing wrong, did I miss a part in the documentation or is this maybe a bugg?
Kind regards,
Pascal
I am getting the error, "The given data was invalid.", on get requests.
When looking at AWS amplify / Google firebase & how they have automatic API support with an admin panel..
Makes me imagine Nova & a fully featured API.. and how this package could maybe fill in that gap.
Like, this package could loop over Nova's resources, relationship fields & construct routes & controllers.
foreach(Nova::resources() as $resource) {
$controller->model = $resource->model
foreach($resource->fields() as $field) {
if($field is hasMany etc) {
$controller->relation = $field->attribute;
}
}
}
php artisan nova:resource Post
, and you have a backend & API
Next all we need is some sort of open api / swagger automagic and we can all quit our jobs.
Just posing the idea. Great package btw :)
This is not an issue with orion. However, orion might be able to implement a solution to this error.
When using route model binding (as orion does behind the scenes), the name of the model cannot be more than 32 characters long.
The following will not work when creating a laravel route:
Route::get('very_long_route_name/{very_long_model_name_will_not_work_with_model_binding}', [SomeController::class, 'show');
I remember looking into this issue in the past, and it looks like Laravel doesn't intend on fixing this... It's actually because of a limitation in symfony.
Would it be possible to add something like modelBindingName('short_model_name')
so that we can avoid this "32 character" limit?
Thanks for all your hard work!
When using soft deletes, I'm getting the following error:
"message": "No query results for model [App\\User].",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
"file": "/var/www/api/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
"line": 222
I have a clue as to why.
In HandlesStandardOperations.php
the method restore
seems to be returning the whole model for the key instead of just the id. Haven't managed to track down why that is yet, need to do a little more source diving!
To test my theory, I added the following to the top of the restore
method and it worked:
HandlesStandardOperations.php
...
public function restore(Request $request, $key)
{
$key = $key->id; // <<<<<
$requestedRelations = $this->relationsResolver->requestedRelations($request);
$query = $this->buildRestoreFetchQuery($request, $requestedRelations);
$entity = $this->runRestoreFetchQuery($request, $query, $key);
...
}
How to filters null value, alternative for the following query.
$users = User::where('active','=', null)->get()
$users = User::whereNotNull('active')->get();
Firstly ,thank for provide such a helpful package!
How can I create post on current authenticated user? Or maybe I must use a relation controller like UserPostsController
?
When using relationship controllers, the model resolution fails when using explicit binding as mentioned here
https://laravel.com/docs/8.x/routing#explicit-binding
The following implementation works around it and uses laravel's internal route resolution logic and should theoretically work with slugs as well. This is only an example and I'm aware we need to update this in a lot of places
protected function runParentFetchQuery(Request $request, Builder $query, $parentKey): Model
{
if ($parentKey instanceof $this->model) {
return $parentKey;
}
/** @var Model $modelClass */
$modelClass = $this->getModel();
return (new $modelClass())->resolveRouteBinding($parentKey);
}
Hi,
I'm using this package for the first time, and its amazing, btw.
But I'm running into a problem (at the moment, I can't figure it out, if is something on my side, or something I'm missing).
I have a Company model, a CompanyAddress model, and an Address model.
That means, Company has many Addresses through my CompanyAddress model.
I've set a controller for CompanyAddressController, that uses the $model = Company::class, and relation 'addresses' (which is my hasManyThrough relation).
The routes are set like this
Orion::hasManyThroughResource('companies', 'addresses', CompanyAddressController::class);
And the error below, is what I'm getting from the request. (using UUID as ids, not in the URL)
Hey,
is there a way to archive searching on related models (nested)?
I have a User, Location and a Address Model and Iam trying to make the users name and the postalcode searchable:
protected function alwaysIncludes() : array
{
return ['user', 'user.location', 'user.location.address'];
}
protected function searchableBy() : array
{
return ['user.name', 'user.location.address.postalcode'];
}
But this will result in an Error:
Call to undefined method App\Models\User::postalcode()
whats the correct way to search on nested models?
Thank you for this wonderful package. I want to use Hashids instead of DB id's. How this can be integrated with your package?
Hi,
I have been using your package for the last 24hs and I love it already. It completely changes the way of building APIs.
I am having trouble when trying to GET, PUT|PATCH or DELETE an either soft|forced deleted record.
I get a 404 response with NotFoundHttpException error page.
How can I prevent this and send a specific json response with whatever error message in it?
Thank you very much for your help and awesome package!!
Hello,
Could you please provide us an example for how to do a custom search.
How to to pass parameters via axios for example. (I'm using Nuxt Js)
Thanks
Hi,
I'm using this package in combination with Laravel Lumen.
I managed to get it working using very few additions to my own project.
I'm running into an issue where dependency 'illuminate/foundation' is not part of the tailflow/laravel-orion composer.json definition.
If you want I can submit a pull request?
In addition I can create a second pull request on how to use this awesome package with Laravel Lumen? Perhaps update the readme?
Thanks in advance!
It will be awesome if there is a default cache or customizable cache.
I was thinking do add it, but I'm not sure if using middleware is gonna be the best for this package or creating custom controllers, configs.
Also if there is a cache option it should be enabled as default, and disable as DisableCache trait.
Hello,
First of all, thank you so much for this amazing package,
I have same issue as this one : #20
I cannot figure out the mistake ! I defined every thing, and it works fine if I put : DisableAuthorization
.
Thanks
I've got a question, I'm using the Orion happily locally with Insomnia to build my endpoints. Works perfect, very happy with this well-thought-through and structured approach.
But now I need to setup authentication. Login, register, reset password etc.
I normally use Fortify for this, but this leverages the X-XSRF-TOKEN approach (web), instead of Bearer (API). I tried setting up Sanctum now too, but I'm getting confused on the best-practice approach.
Any thoughts or experiences that can help me move forward?
Thanks.
First off: so happy with this package. Exactly what the doctor ordered.
The one thing I'm uncertain of (happy to hear your thoughts) is the default JSON response. I'm used to it container a status, message, and data object. And for errors showing status, message and errors object (through a custom exception). So far, though that might be because I drew it into an existing project, I'm getting non-JSON exceptions. And successful calls do not contain status or message (e.g. 200, resource update, data{}).
So I'd be curious to learn what conventions are followed in this project.
Keep it up!
Laravel supports restful-nested-resources, which are configured by chaining them with dots.
Their behaviour is already partially supported with all those great relation-routes, but they only support one level of nesting/relation.
As I need another nesting level I tried using laravels dot notation, which did work partially, which is even worse than failing all together, as the results look correct, but are simply wrong.
I am adding new routes like:
Orion::belongsToManyResource('as.bs','cs', \App\Http\Controllers\Api\BCController::class);
which creates the expected routes like:
Method | URI | Name | Action |
---|---|---|---|
GET/HEAD | api/as/{a}/bs/{b}/cs | as.bs.cs.index | App\Http\Controllers\Api\BCController@index |
POST | api/as/{a}/bs/{b}/cs | as.bs.cs.store | App\Http\Controllers\Api\BCController@store |
... | ... | ... | .... |
GET/HEAD | api/as/{a}/bs/{b}/cs/{c?} | as.bs.cs.show | App\Http\Controllers\Api\BCController@show |
PUT/PATCH | api/as/{a}/bs/{b}/cs/{c?} | as.bs.cs.update | App\Http\Controllers\Api\BCController@update |
... | ... | ... | ... |
(I am not sure why the c is marked optional, but thats not the point)
GET api/as/1/bs/2/cs
Listing of all Cs of B2 (given B2 is related to A1)
Listing of all Cs of B1 (even if B1 is not related to any A)
api/as/1/bs/2/cs/3
C3 (given C3 is related to B2 and B2 is related to A1)
C2 (with C2 being related to B1)
I'd expect the APolicy to be checked too, but it doesn't seem to be.
I am a bit sad for the controller not working out of the box and me having to try getting it to work as expected or writing it myselfe by hand again -- but thats just because of how awesome orion is and how much time it did save me at all the other controllers, which did work just out of the box. Great work - so much appreciated!
Following response does not trigger hookReponds
protected function beforeSave(Request $request, $model)
{
return response()->json(['message' => 'Invalid data'], 400);
}
It is suggested to check response type with \Symfony\Component\HttpFoundation\Response instead of Illuminate\Http\Response;
Hi!
I'm new to APIs, but this package seems pretty cool and structured in its setup.
I have a question though.
Currently, in my LabelController in the store() method, I call a StoreLabelAction. This dedicated single action class invokes the store and returns the Label model. I do this so that whenever I create a label, I have a single class that I can call. Like this:
public function store(LabelRequest $request, StoreLabelAction $action)
{
$label = $action->execute($request->validated());
return response($label, 200);
}
My StoreLabelAction looks like this (simplified):
public function execute(array $data) : Label
{
if(Label::where('title', $data['title'])->first())
{
throw new LabelNotUniqueException("Label should be unique.");
}
$label = new Label;
$label->title = $data['title'];
$label->save();
return $label;
}
I feel this a clean way of doing so, but following the docs with the performStore() I seem to be lost on how to implement this logic. If at all. What am I missing?
Hello, am trying to use the laravel orion batch update functionality. it works fine on default but when i use change the keyName to slug it gives error "Argument 3 passed to Orion\Http\Controllers\Controller::performUpdate() must be of the type array, null given" what am i doing wrong?
am using postman for testing, bellow is my postman setup
Body -> row -> json
{
"resources": {
"nigeria": {
"description": "new description"
},
"gambia": {
"description": "new description"
}
}
}
URL: Patch -> http://elo.test/api/countries/batch
Hi,
Is it possible to include in the list of operators ILIKE.
The key word ILIKE can be used instead of LIKE to make the match case-insensitive. This is not in the SQL standard but is a PostgreSQL extension.
When hitting an Orion index route, I'm getting the error:
Argument 1 passed to Orion\\Http\\Controllers\\Controller::index() must be an instance of Orion\\Http\\Requests\\Request
Does this mean that we are unable to use laravels Illuminate\Foundation\Http\FormRequest
class for requests?
If not, that's totally fine! Might just need to add that to the docs here:
https://tailflow.github.io/laravel-orion-docs/guide/security.html#authentication
In Laravel you can use the following code to gather the amount of relationship items without loading the full model/data:
$threads = Thread::withCount(['posts'])->get();
We currently have:
protected function includes(): array
{
return [
'posts',
];
}
protected function alwaysIncludes(): array
{
return [
'posts',
];
}
Please add something like:
protected function includesCount(): array
{
return [
'posts',
];
}
protected function alwaysIncludesCount(): array
{
return [
'posts',
];
}
Am trying to override the buildIndexFetchQuery method on the controller and I got the following error message
'
Could not check compatibility between App\Http\Controllers\PostController::buildIndexFetchQuery(Illuminate\Http\Request $request, array $requestedRelations): App\Http\Controllers\Builder and Orion\Http\Controllers\Controller::buildIndexFetchQuery(Orion\Http\Requests\Request $request, array $requestedRelations): Illuminate\Database\Eloquent\Builder, because class App\Http\Controllers\Builder is not available
Any help?
Hi!
As far as I understand, there's no way to search in relations in different databases. When the QueryBuilder class applies the search to the query builder it uses the whereHas query builder function, but there's no way to specify another connection for the relation if needed.
I stand corrected if I'm wrong :)
The following code does not work.
protected function afterIndex(Request $request, Paginator $entities)
{
$entities->appends('key', 'value');
}
How to filter JSON attributes?
I need support for JSON Where
Link: https://laravel.com/docs/8.x/queries#json-where-clauses
Hello guys, I'm having trouble binding the parameters passed in the URL, even setting the getRouterKeyName to the name of the parameter, Orion is unable to resolve and presents the following error:
This is the URL:
http://localhost/api/customers/e34aa4ad-843e-43f6-b7d7-87e4928a46a2/settings/1472ef28-1d9d-4e81-9b47-8c4ee2d9f5e3
As you can see in the image, orion tries to search for a setting with a customer ID.
Can someone help me?
I have two models posts and comments with relationship oneToMany. A post hasManyComments and a Comment Belongs to a Post.
I have defined in the Post Model, protected $with = 'comments'., but when I execute, the Eager loading is not working. Do we have a fix around?
As example i had to disable any BATCH routes for some reason. How can i make this?
Is it currently possible to disable policy checks for a given endoint?
My use case is for indexing users. When I hit api/users
However, I don't want to set my viewAny
policy to return true;
because that feels a bit risky.
...
I may be asking for too much... Honestly, this extension is an absolute dream. I've spent the last 4 days converting our entire API to orion because the benefits are insane!
A awesome tool pack for API, do you have any plan to implement API documentation like (swagger)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.