Is there a way to get all the relations and fields of particular model in laravel? - laravel

I am trying to create a script that could help me generate a GraphQL schema with all fields and relations exist in the models.
if I could get that, php-lighthouse would help me for the rest of the work.

There is no way to get all relations of a particular Eloquent model without the user specifying them in some way, such as an attribute on the model that holds all relation names, or type-hinting those methods returning a relation. See laravel-eloquent-to-graphql for an example.
You can however get all fields of a model (that are saved in the database) by inspecting its table.
If you're looking for a GraphQL generator, there are Laravel Bakery and laravel-eloquent-to-graphql. Laravel Bakery generates a GraphQL schema on-the-fly, while laravel-eloquent-to-graphql generates a GraphQL schema statically.
There is also Lighthouse-Utils, which can generate queries and mutations for already-defined types.

Related

How to create a GraphQL query that returns data from multiple tables/models within one field using Laravel Lighthouse

Im trying to learn GraphQL with Laravel & Lighthouse and have a question Im hoping someone can help me with. I have the following five database tables which are also defined in my Laravel models:
users
books
user_books
book_series
book_copies
I'd like to create a GraphQL endpoint that allows me to get back an array of users and the books they own, where I can pull data from multiple tables into one subfield called "books" like so:
query {
users {
name
books {
title
issue_number
condition
user_notes
}
}
}
To accomplish this in SQL is easy using joins like this:
$users = User::all();
foreach ($users as $user) {
$user['books'] = DB::select('SELECT
book_series.title,
book.issue_number
book_copies.condition,
user_books.notes as user_notes
FROM user_books
JOIN book_copies ON user_books.book_copy_id = book_copies.id
JOIN books ON book_copies.book_id = books.id
JOIN book_series ON books.series_id = book_series.id
WHERE user_books.user_id = ?',[$user['id']])->get();
}
How would I model this in my GraphQL schema file when the object type for "books" is a mashup of properties from four other object types (Book, UserBook, BookCopy, and BookSeries)?
Edit: I was able to get all the data I need by doing a query that looks like this:
users {
name
userBooks {
user_notes
bookCopy {
condition
book {
issue_number
series {
title
}
}
}
}
}
However, as you can see, the data is separated into multiple child objects and is not as ideal as getting it all in one flat "books" object. If anyone knows how I might accomplish getting all the data back in one flat object, Id love to know.
I also noticed that the field names for the relationships need to match up exactly with my controller method names within each model, which are camelCase as per Laravel naming conventions. Except for my other fields are matching the database column names which are lower_underscore. This is a slight nitpick.
Ok, after you edited your question, I will write the answer here, to answer your new questions.
However, as you can see, the data is separated into multiple child objects and is not as ideal as getting it all in one flat "books" object. If anyone knows how I might accomplish getting all the data back in one flat object, Id love to know.
The thing is, that this kind of fetching data is a central idea of GraphQL. You have some types, and these types may have some relations to each other. So you are able to fetch any relations of object, in any depth, even circular.
Lighthouse gives you out of the box support to eloquent relations with batch loading, avoiding the N+1 performance problem.
You also have to keep in mind - every field (literally, EVERY field) in your GraphQL definition is resolved on server. So there is a resolve function for each of the fields. So you are free to write your own resolver for particular fields.
You actually can define a type in your GraphQL, that fits your initial expectation. Then you can define a root Query field e.g. fetchUsers, and create you custom field resolver. You can read in the docs, how it works and how to implement this: https://lighthouse-php.com/5.2/the-basics/fields.html#hello-world
In this field resolver you are able to make your own data fetching, even without using any Laravel/Eloquent API. One thing you have to take care of - return a correct data type with the same structure as your return type in GraphQL for this field.
So to sum up - you have the option to do this. But in my opinion, you have to write more own code, cover it with tests on you own, which turns out in more work for you. I think it is simpler to use build-in directives, like #find, #paginate, #all in combination with relations-directives, which all covered with tests, and don't care about implementation.
I also noticed that the field names for the relationships need to match up exactly with my controller method names within each model, which are camelCase as per Laravel naming conventions.
You probably means methods within Model class, not controller.
Lighthouse provides a #rename directive, which you can use to define different name in GraphQL for your attributes. For the relation directives you can pass an relation parameter, which will be used to fetch the data. so for your example you can use something like this:
type User {
#...
user_books: [Book!]! #hasMany(relation: "userBooks")
}
But in our project we decided to use snak_case also for relations, to keep GraphQL clean with consistent naming convention and less effort

How to fetch data from relationship in strapi.js?

I have created two content type builder which are category and sub-category respectively. While adding sub-category I had define one relationship which is one-to-many.
After creating successfully, I found that the basic CRUD API has been created and it works fine.
Now I need to find data like if I pass category-id then it has to return me it's all sub-category list.
Well, for this I can also write API manually, But I thought that strapi provides a feature of relationship though it may have some way to fetch data from the relationship table. In my app, I had set up a project with MySQL.
Expected output: Need a way to fetch data from a relation without writing custom API. Looking for inbuilt feature of strapi.
You have to use deep filtering.
📚Here is the documentation https://strapi.io/documentation/3.0.0-beta.x/guides/filters.html#deep-filtering
So you will be able to do /categories?sub-category.id=[your id]

Models responsability

I have a doub about Laravel. The models are used to define the relationships between the models like hasMany, belongsTo, etc. Also the models are used to define the fillable fields. But he models are only for that? Because I already check some examples that it seems that some queries are executed in the models instead of the controller so Im not understanding if the models should also have the querying of the relationships or not. Can you give a help to understand better what is the correct use of models (what should be placed in the models)?
Its same way to execute queries on model or controller. Written queries in model make your controller more clean. We can write mutator, accessor or query scope in eloquent model. Correct me if I'm wrong.
Visit https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Model.html
You can refer this documentation, it's quite helpful if you want to know deep basics and responsibilities about particular part in Laravel.
Models are mostly used to make an outlook of the data i.e what fields are going to be saved in the database and we also use it to associate the relationships with other related data as you already know but we also use it to alter the values that are either going in/out of the data base which you can check in the documentation in link bellow https://laravel.com/docs/5.6/eloquent-mutators
the main purpose is to divide the code between controller and model (were it best fit to be)

Laravel Dynamic Eager Loading for Dynamic Relationships

Laravel Version: 5.5
PHP Version: 7+
Database Driver & Version: mysql 5.7+
Scenario:
I have a SaaS application that has flexible database structure, so its fields are bound to change, especially given it has a Json field (for any extra database structure to be created from client side of the application), including relationship based fields. so Account Table can have dynamically created employee_id field, and thus the need to access relationships dynamically
Problem:
I need to EagerLoad models based on this dynamic relationship. If I had something like this:
// Account Model
public function employee(){
return $this->belongsTo(App\Employee);
}
it would be easy. But what I have is this:
public function modelBelongsTo(){
return $this->belongsTo($dynamicClassName, $dynamicForeignKey);
}
Now if I eager load this, I'll get Account Model instance with related Employee on key modelBelongsTo. This is how Eloquent Names based on the function of eagerload. But after this I cannot use this function again to eagerload a second model because it'll just overwrite results on modelBelongsTo key.
Possible Solution Directions:
1) Can I Somehow change laravel's process to use a name I provide?
or
2) Can I write functions on the fly to overcome this so I'll write employee function on the fly?
or
3) Worst Case Scenario: I iterate over all records to rename their keys individually because I am using a pagination, it wouldn't that big of a deal to loop over 10 records.
Us a morph relationship
define the various dynamic classnames say
Employee
Boss
Morph works by having the related key and the table name stored in the parent table, it means to relate them you have to use a join or an orm and you cant have foreign key constraint on it as it links to different tables.
then have your account have morphs where
we have
Account
as top class
then we have
EmployeeAccount, BossAccount
which have their relation to boss and employee
then in Account have morphto relation call it specificAccount()
to which in its child morphs have the morph relation to Account
then add it to $with so to eager load them so when fetching account you could simply do
$account ->specificAccount
to get its morph child. which is nullable
This is totally dynamic such that if you have other classes in future you can just add and add the morph relationship. This may be applied to any reflection or runtime evaluated and loaded classes/code though it is not advisable to do this, as you can always edit code to create new functionality without affecting previous.

How to create unique relationship using NeoEloquent

I have just started using Laravel. I have not used Laravel Eloquent before. So I am directly using it on graph database using NeoEloquent.
I know I can create relationship using hasMany() and attach() methods. But I want to create relationship only once. Has anybody used NeoEloquent for creating Unique Relationship.
You may use the hasOne()relationship instead of hasMany() which will ensure that only one relationship of the specified type exists for the model.

Resources