Laravel relationship with custom method - sql

Table project:
project_id (int)
requestor_id (uuid)
Table requestor:
requestor_id (uuid)
Model Project:
public function requestor() {
return $this->hasOne('App\Models\Requestor', 'requestor_id', 'requestor_id');
}
Model Requestor has one method:
// this method return object users info from ldap
public function getLdapAttribute() {
$ldapWrapper = new LdapWrapper();
return $ldapWrapper->checkIfUuidExists($this->requestor_id, true);
}
Select all projects with requestor relationship:
$query = (new Project)->newQuery()->with(['requestor'])->get();
And Question is:
How can I select all projects with requestor relationship and on every requestor object call method getLdapAttribute and return all as one object?
Thank you very much :)

You can put the name of that "Ldap" attribute in the $appends array of the App\Requestor Class and Eloquent will automatically append a property named ldap with the value ,of the returned for the getLdapAttribute method.
Link to the Official Laravel Documentation for this Eloquent feature !

As SQL query of getLdapAttribute method is not specified, we can fetch projects first, and then iterate over and get that attribute.
If SQL query of getLdapAttribute is given then we can get all the data in one query (here we get attributes after the first query of fetching projects).
$projects = Project::with(['requestor'])
->get()
->each(function ($project) {
$project->requestor->getLdapAttribute();
});

Related

TYPO3 6.2 get Properties with values of Table

I have the following problem: When I use a Model/Repository with a different mapping, I don't get any property and values.
I've mapped the Repository to fetch the data from table sys_files.
I do get the UID, I also do get the PID. Unfortunately, I do not get any other property or the value.
My Repository is a simple Repository mapped to sys_files.
Unfortunately, I do not get any orther property.
Thanks a lot.
Greetz
Have you defined the mapping in the ext_typoscript_setup.txt?
config.tx_extbase {
persistence {
classes {
Vendor\Package\Domain\Model\MyModel {
mapping {
tableName = sys_file
}
}
}
}
}
You also need to assign the needed fields in your domain model.
namespace Vendor\Package\Domain\Model;
class MyModel
{
/**
* #var string
*/
protected $identifier;
public function getIdentifier()
{
return $this->identifier;
}
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
}
}
There is a checklist when you mapping a model to a table:
1. Create the ext_typoscript_setup.txt file in the extension root path.
There you have to write the following code:
config.tx_extbase{
persistence {
classes {
YourModel.mapping{
table = table_you_want_to_map
}
}
}
}
Avoid to add backslash before model namespace
3. Clear cache from install tool. If nothing happens, then, try to delete the typo3temp/autoload folder.
4. The fields from the model should be camelCase.
Example of field: field_name in your model will be fieldName
5. Check the getters in your model.
Okay, problem solved - almost.
I can't get hash values. I don't know why but it is how it is.
I get the values of each column except "identifier_hash", "folder_hash". These attributes are always NULL.
Now I only have to make a new file_reference record in my db when I add a new relation.

Yii2 REST API relational data return

I've set up Yii2 REST API with custom actions and everything is working just fine. However, what I'm trying to do is return some data from the API which would include database relations set by foreign keys. The relations are there and they are actually working correctly. Here's an example query in one of the controllers:
$result = \app\models\Person::find()->joinWith('fKCountry', true)
->where(..some condition..)->one();
Still in the controller, I can, for example, call something like this:
$result->fKCountry->name
and it would display the appropriate name as the relation is working. So far so good, but as soon as I return the result return $result; which is received from the API clients, the fkCountry is gone and I have no way to access the name mentioned above. The only thing that remains is the value of the foreign key that points to the country table.
I can provide more code and information but I think that's enough to describe the issue. How can I encode the information from the joined data in the return so that the API clients have access to it as well?
Set it up like this
public function actionYourAction() {
return new ActiveDataProvider([
'query' => Person::find()->with('fKCountry'), // and the where() part, etc.
]);
}
Make sure that in your Person model the extraFields function includes fKCountry. If you haven't implemented the extraFields function yet, add it:
public function extraFields() {
return ['fKCountry'];
}
and then when you call the url make sure you add the expand param to tell the action you want to include the fkCountry data. So something like:
/yourcontroller/your-action?expand=fKCountry
I managed to solve the above problem.
Using ActiveDataProvider, I have 3 changes in my code to make it work.
This goes to the controller:
Model::find()
->leftJoin('table_to_join', 'table1.id = table_to_join.table1_id')
->select('table1.*, table_to_join.field_name as field_alias');
In the model, I introduced a new property with the same name as the above alias:
public $field_alias;
Still in the model class, I modified the fields() method:
public function fields()
{
$fields = array_merge(parent::fields(), ['field_alias']);
return $fields;
}
This way my API provides me the data from the joined field.
use with for Eager loading
$result = \app\models\Person::find()->with('fKCountry')
->where(..some condition..)->all();
and then add the attribute 'fkCountry' to fields array
public function fields()
{
$fields= parent::fields();
$fields[]='fkCountry';
return $fields;
}
So $result now will return a json array of person, and each person will have attribute fkCountry:{...}

Laravel 5 - creating two tables during registration

In my database design, I have two tables, People & Auth. The Auth table holds authentication information and the person_id while the People table holds all other information (name, address, etc). There is a one-to-one relationship between the tables as seen in the models below.
The reason I have separated the data into two tables is because in my
application, I will have many people who do not have authentication
capabilities (customers to the user).
App/Auth.php
class Auth extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
public function person() {
$this->belongsTo('Person');
}
}
App/Person.php
class Person extends Model
{
public function auth() {
$this->hasOne('Auth');
}
}
In my AuthController::create() method, I am attempting to populate both models with the user supplied information like this:
protected function create(Request $request)
{
$person = \App\Person::create($request->all());
$auth = new \App\Auth;
$auth->fill($request->all());
$auth->person_id = $person->id;
$auth->save();
return $person;
}
In my application, I would like to authorize a user and pass a $user object as the authenticated person to subsequent routes. Am I doing this correctly? Is this the best way? There's cookies and bonus points if you can also explain how to retrieve the $user object after authentication...Auth table data is not needed in the $user object.
EDIT
I have changed my config/Auth.php file to reflect the changes as noted in the answers below (thx #user3702268). However, I have now found an error with my controller. In the AuthController::create() method, I am returning my App/Person object and this throws an ErrorException seeing as how App/Person does not implement the Authorizable trait. I do not want my App/Person object to be authorizable, but it is the object that I want returned as the authenticated $user in my views. How? Shall I simply override the postRegister method or is there a more Laravel way?
EDIT 2
I'm now returning the $auth object which uses the authorizable trait. In my views/controllers I'm trying to access the Person using Auth::user()->person but getting Class 'Person' not found errors
You should replace the App\User Class in config/auth.php line 31 the class that contains the username and password:
'model' => App\User::class,
to
'model' => App\Auth::class,
Be sure to encrypt the password before saving by using the bcrypt($request->get('password')) helper or Hash::make($request->get('password')). Then you can authenticate by calling:
Auth::attempt([$request->get('username'), $request->get('password')]);
You can retrieve the authenticated user using this:
Auth::user()

How to map Eloquent with other tables?

This is the first time when i use ORM, so i wondering if it is possible to map it to other tables...
For example i have currently logged user. It is connected to the POSTS table through links table. For example if i want to select posts i do sql like this:
SELECT
`posts`.`id`', `posts`.`Name`, `posts`.`Description`
FROM
`links`,
`posts`
WHERE
`links`.`user_id` = 1 AND `links`.`post_id` = `posts`.`id`
How to extend Eloquent that if i request Posts::all() it would return posts only for current user...
You can define a query scope in your POST modal
public function scopeOfUser($query,$user_id)
{
return $query->join('links', 'links.post_id', '=', 'posts.id')
->where('links.user_id', '=', $user_id)
->select('posts.id', 'posts.Name', 'posts.Description');
}
Then use it like this:
$posts = POST::OfUser(1)->get();
Your post is a bit confusing but I hope my answer addresses it as you expect.
Warning:
Please refer to Laravel's (Many to Many) Relationship documentation for details.
To make things simple and comply with the Laravel convention, I strongly suggest you to use post_userinstead of link as the pivot table (post_user table should have user_id and post_id as columns).
You don't have to define a corresponding pivot model (that's the convention).
The following models are meant to map to respectfully the tables users and posts.
User Model:
in app/model/user.php (already there, just add the relationship definition)
class User extends Eloquent {
...
public function posts()
{
return $this->belongsToMany('Post');
}
...
}
Post Model:
in app/models/post.php (to be created of course).
...
class Post extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
}
...
Retrieval of a user's posts:
Usually, you do the following in Laravel to get the current logged user:
$user = Auth::user(); // a User model / record
Assuming $user is of type User (Model), you can retrieve all its posts using:
$user->posts(); // a Collection

Doctrine 2 ArrayCollection filter method

Can I filter out results from an arrayCollection in Doctrine 2 while using lazy loading? For example,
// users = ArrayCollection with User entities containing an "active" property
$customer->users->filter('active' => TRUE)->first()
It's unclear for me how the filter method is actually used.
Doctrine now has Criteria which offers a single API for filtering collections with SQL and in PHP, depending on the context.
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#filtering-collections
Update
This will achieve the result in the accepted answer, without getting everything from the database.
use Doctrine\Common\Collections\Criteria;
/**
* #ORM\Entity
*/
class Member {
// ...
public function getCommentsFiltered($ids) {
$criteria = Criteria::create()->where(Criteria::expr()->in("id", $ids));
return $this->getComments()->matching($criteria);
}
}
The Boris Guéry answer's at this post, may help you:
Doctrine 2, query inside entities
$idsToFilter = array(1,2,3,4);
$member->getComments()->filter(
function($entry) use ($idsToFilter) {
return in_array($entry->getId(), $idsToFilter);
}
);
Your use case would be :
$ArrayCollectionOfActiveUsers = $customer->users->filter(function($user) {
return $user->getActive() === TRUE;
});
if you add ->first() you'll get only the first entry returned, which is not what you want.
# Sjwdavies
You need to put () around the variable you pass to USE. You can also shorten as in_array return's a boolean already:
$member->getComments()->filter( function($entry) use ($idsToFilter) {
return in_array($entry->getId(), $idsToFilter);
});
The following code will resolve your need:
//$customer = ArrayCollection of customers;
$customer->getUsers()->filter(
function (User $user) {
return $user->getActive() === true;
}
);
The Collection#filter method really does eager load all members.
Filtering at the SQL level will be added in doctrine 2.3.