Query chaining multiple tables - php

I am trying to get the users (ID 1) trip data from the user_trips table, along with that trips flights in the user_flights table, and I am getting the airports.name using the flight_from and flight_to foreign keys.
I've tried numerous ways, and I assume it's very easy but this is my first Laravel project. I've read the documentation and watched LaraCasts but I just can't figure out the right combination.
The $user_flights variable returns:
[
{
"id":1,
"user_trips_id":6,
"flight_from":1,
"flight_to":14,
"flight from":
{
"id":1,
"code":"AIZ",
"name":"Lee C Fine Memorial",
"city":"Lake Of The Ozarks",
"country":"United States"
},
"flightto":
{
"id":14,
"code":"AEX",
"name":"Alexandria Intl Arpt",
"city":"Alexandria",
"country":"United States"
}
},
{
"id":2,
"user_trips_id":7,
"flight_from":1,
"flight_to":22,
"flight from":
{
"id":1,
"code":"AIZ",
"name":"Lee C Fine Memorial",
"city":"Lake Of The Ozarks",
"country":"United States"
},
"flightto":
{
"id":22,
"code":"ADG",
"name":"Lenawee County Arpt",
"city":"Adrian",
"country":"United States"
}
}
]
I need it to return something like this (I think):
[
{
"id":6,
"user_id":1,
"name":"My Trip",
"flights":
{
"id":1,
"user_trips_id":6,
"flight_from":1,
"flight_to":14,
"flight from":
{
"id":1,
"code":"AIZ",
"name":"Lee C Fine Memorial",
"city":"Lake Of The Ozarks",
"country":"United States"
},
"flightto":
{
"id":14,
"code":"AEX",
"name":"Alexandria Intl Arpt",
"city":"Alexandria",
"country":"United States"
}
}
}
]
Schema
# `user_trips` table
Schema::create('user_trips', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->index();
$table->text('name');
});
# `user_flights` table
Schema::create('user_flights', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_trips_id')->unsigned();
$table->integer('flight_from')->unsigned();
$table->integer('flight_to')->unsigned();
$table->foreign('user_trips_id')->references('id')->on('user_trips')->onDelete('cascade');
$table->foreign('flight_from')->references('id')->on('airports')->onDelete('cascade');
$table->foreign('flight_to')->references('id')->on('airports')->onDelete('cascade');
});
TripBuilderController
<?php
namespace App\Http\Controllers;
use App\Airport;
use App\UserFlights;
/**
* Class TripBuilderController
*
* #package App\Http\Controllers
*/
class TripBuilderController extends Controller
{
/**
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index()
{
$airports=Airport::all();
# Returns all `user_trips` and `user_flights`.
# I need to return only `user_trips`.`user_id` associated to user ID 1,
# and the `user_flights` associated to the user's `user_trips`.
$user_flights=UserFlights::with('flightfrom')->with('flightto')->get();
return view('welcome', compact('airports', 'user_flights'));
}
}
UserTrips Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* Class UserTrips
*
*/
class UserTrips extends Model
{
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps=FALSE;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable=[
'name',
'user_id'
];
/**
* #param UserFlights $user_flights_obj
* #return Model
*/
public function addFlight(UserFlights $user_flights_obj)
{
return $this->userflights()->save($user_flights_obj);
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function userflights()
{
return $this->hasMany(UserFlights::class);
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* #return mixed
*/
public function addTrip()
{
# Retrieve the trip by the attributes, or instantiate a new instance...
$trip_obj=$this->firstOrNew(['user_id'=>1]);
if(!$trip_obj->id)
{
$trip_obj->name='My Trip';
$trip_obj->save();
}
return $trip_obj;
}
}
UserFlights Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* Class UserFlights
*
*/
class UserFlights extends Model
{
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps=FALSE;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable=[
'flight_from',
'flight_to'
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function flightfrom()
{
return $this->belongsTo(Airport::class, 'flight_from');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function flightto()
{
return $this->belongsTo(Airport::class, 'flight_to');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function usertrip()
{
return $this->belongsTo(UserTrips::class, 'user_trips_id');
}
}

User::find(1)->userTrips()->with('userflights', 'userflights.flightfrom', 'userflights.flightto')->get();
or calling directly from UserTrips
UserTrips::whereUserId(1)->with('userflights', 'userflights.flightfrom', 'userflights.flightto')->get();
with() gives you eager loading and when you convert a model a JSON, it includes any of the eager loaded models you specified.

Related

How can I achieve this design in Flutter app with response coming from Laravel Api?

I am trying to develop an app for schools and parents where the class teachers will be able to upload pictures of a student when a student check-in to school and check-out from school. This app will have a backend which will be built using laravel 9. The whole app is based on API.
Image of App User Interface here
I want to show photos of check-in and check-out side by side based on the date. If check-out is not updated yet, then the check-in image will be there and the check-out section will be empty.
Here is the JSON response that I am working with:
{
"data": [
{
"id": 1,
"child_id": 1,
"date": "18-08-2022",
"time": "08:49:51",
"status": "check_in",
"image": "https://via.placeholder.com/640x480.png/008833?text=kids+et"
},
{
"id": 6,
"child_id": 1,
"date": "18-08-2022",
"time": "10:24:38",
"status": "check_out",
"image": "https://via.placeholder.com/640x480.png/00ffdd?text=kids+veritatis"
}
]
}
Laravel Controller:
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreCheckInOutRequest;
use App\Http\Requests\UpdateCheckInOutRequest;
use App\Http\Resources\V1\CheckInOut\CheckInOutResource;
use App\Models\CheckInOut;
use App\Services\V1\CheckInOutQuery;
use Illuminate\Http\Request;
class CheckInOutController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$filter = new CheckInOutQuery();
$queryItems = $filter->transform($request); //[['column', 'operator', 'value']]
if (count($queryItems) == 0) {
return response()->json(['message' => 'No child id provided'], 400);
} else {
return CheckInOutResource::collection(CheckInOut::where($queryItems)->orderBy('date', 'desc')->get());
}
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(StoreCheckInOutRequest $request)
{
$checkInOut = CheckInOut::create($request->all());
return response()->json(['message' => 'Check in & out status created successfully.', 'data' => $checkInOut], 201);
}
/**
* Display the specified resource.
*
* #param \App\Models\CheckInOut $checkInOut
* #return \Illuminate\Http\Response
*/
public function show(CheckInOut $checkInOut)
{
return new CheckInOutResource($checkInOut);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Models\CheckInOut $checkInOut
* #return \Illuminate\Http\Response
*/
public function update(UpdateCheckInOutRequest $request, CheckInOut $checkInOut)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param \App\Models\CheckInOut $checkInOut
* #return \Illuminate\Http\Response
*/
public function destroy(CheckInOut $checkInOut)
{
//
}
}
Laravel API Resource:
<?php
namespace App\Http\Resources\V1\CheckInOut;
use Illuminate\Http\Resources\Json\JsonResource;
class CheckInOutResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'child_id' => $this->child_id,
'date' => date('d-m-Y', strtotime($this->date)),
'time' => $this->time,
'status' => $this->status,
'image' => $this->image
];
}
}
Database Migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('check_in_outs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('child_id');
$table->date('date');
$table->time('time');
$table->string('status')->comment('check_in, check_out');
$table->string('image')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('check_in_outs');
}
};
CheckInOut Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CheckInOut extends Model
{
use HasFactory;
protected $fillable = [
'child_id',
'date',
'time',
'status',
'image'
];
protected $hidden = [
'created_at',
'updated_at'
];
public function child()
{
return $this->belongsTo(Child::class);
}
}
Please help me, how can I design my API response and handle the API response to achieve my goal of design in flutter? Image of App User Interface here
The backend information is irrelevant, we only have to take into account the response in json
Create a model of your response. (You can use https://quicktype.io/ and paste your json output to get the Model class in Dart, the class you will get already has methods to map the objects from json.)
The design is not difficult, you should visit https://docs.flutter.dev/development/ui/widgets/material.
API requests can be done with https://pub.dev/packages/http and you can show images with https://docs.flutter.dev/cookbook/images/network-image
. Hope it helps your asking for a lot of information.

Array to string conversion in Orchid Software attachments in Laravel

I am trying to attach documents to a model when saving. I am getting array to string conversion erro. Because, it puts the documents Ids in to an array.
Here is my model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Orchid\Screen\AsSource;
use App\Models\Seller;
use Orchid\Attachment\Models\Attachment;
use Orchid\Attachment\Attachable;
use Orchid\Filters\Filterable;
use Orchid\Metrics\Chartable;
use App\Orchid\Presenters\PropertyPresenter;
use Laravel\Scout\Searchable;
class Property extends Model
{
use HasFactory;
use AsSource, Attachable,Filterable;
use Chartable;
/**
* #var array
*/
protected $fillable = [
'property_name',
'property_type',
'property_city',
'property_address',
'property_area',
'seller_id',
'property_cost',
'property_price',
'property_rent_price',
'status',
'contracts',
'images'
];
/**
* Get the parent seller of the property.
*/
public function seller()
{
return $this->belongsTo(Seller::class);
}
/**
* Name of columns to which http sorting can be applied
*
* #var array
*/
protected $allowedSorts = [
'property_name',
'property_type',
'property_city',
'status',
'created_at',
'updated_at'
];
/**
* #param Builder $query
*
* #return Builder
*/
public function scopeActive(Builder $query)
{
return $query->where('status', 'Available');
}
/**
* #param Builder $query
*
* #return Builder
*/
public function scopeStatus(Builder $query)
{
return $query->where('status', '!=', 'Sold');
}
// Many-to-Many (no foreign id on table, should be uploaded with groups() function)
public function documents()
{
return $this->hasMany(Attachment::class)->where('group','contracts');
}
/**
* Get the presenter for the model.
*
* #return PropertyPresenter
*/
public function presenter()
{
return new PropertyPresenter($this);
}
/**
* Get the indexable data array for the model.
*
* #return array
*/
public function toSearchableArray()
{
$array = $this->toArray();
// Customize array...
return $array;
}
}
Here are the form elements
Upload::make('property.contracts')
->title('Documents')
->maxFileSize(2)
->targetId()
->targetRelativeUrl()
->groups('documents')
->acceptedFiles('image/*,application/pdf,.psd'),
And here is the save/update function
/**
* #param Property $property
* #param Request $request
*
* #return \Illuminate\Http\RedirectResponse
*/
public function createOrUpdate(Property $property, Request $request)
{
$property->fill($request->get('property'))->save();
$property->attachment()->syncWithoutDetaching(
$request->input('property.contracts', [])
);
Alert::info('You have successfully created an property.');
return redirect()->route('platform.property.list');
}
Finally here is the migration file
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('properties', function (Blueprint $table) {
$table->id();
$table->string('property_name');
$table->string('property_type');
$table->string('property_city');
$table->text('property_address');
$table->double('property_area',15,2);
$table->unsignedBigInteger('seller_id');
$table->double('property_cost', 20.3);
$table->double('property_price');
$table->double('property_rent_price')->nullable();
$table->string('contracts')->nullable();
$table->string('images')->nullable();
$table->string('status')->default('Available');
$table->timestamps();
$table->foreign('seller_id')->references('id')->on('sellers');
});
}
It gives the array to string conversion error and here is the request body:
{ "property_name": "Villa02", "property_type": "residential", "property_city": "Garoowe", "property_address": "Test", "property_area": "12000", "seller_id": "1", "property_cost": "43000", "property_price": "50000", "property_rent_price": "300", "status": "Available", "contracts": [ "67" ], "images": "/storage/2022/04/15/e3cbed3acbfec1d40c54aa57aa651a05c80d6586.png" }
Thanks in advance.
Just unset the array before filling the model
public function createOrUpdate(Property $property, Request $request)
{
$propertyInputs = $request->get('property');
$contacts = $propertyInputs['contracts']??[];
unset($propertyInputs['contracts']);
$property->fill($propertyInputs)->save();
$property->attachment()->syncWithoutDetaching($contacts);
Alert::info('You have successfully created an property.');
return redirect()->route('platform.property.list');
}

How to delete original file after converting image using spatie/media-library in Laravel

I am using Laravel 8 and I was wondering if there is anyway to automatically delete original image after it has converted in Spatie Media Library? it's currently taking up my storage space so I want to be able to delete original images.
here's the model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Image\Manipulations;
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\Models\Media;
class Profile extends Model implements HasMedia
{
use HasMediaTrait, softDeletes;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'user_id',
'theme_id',
'name',
'username',
'location',
'bio',
'views',
];
protected $appends = [
'avatar_url',
'route',
];
protected $with = [
'links',
'theme',
];
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'username';
}
/**
* #return mixed
*/
public function getAvatarUrlAttribute()
{
if ($this->hasMedia('avatar')) {
return $this->getFirstMedia('avatar')->getUrl('cropped');
}
return asset('/images/avatar.png');
}
/**
* #return mixed
*/
public function getRouteAttribute()
{
return route('profiles.show', $this);
}
/**
* #return mixed
*/
public function getKeywordsAttribute()
{
$keywords = $this->links
->map(function ($link) {
return "{$link->name} {$this->name}";
})
->toArray();
$keywords[] = $this->name;
return implode(',', $keywords);
}
/**
* Get all of the profile's links.
*
* #param string $order
*
* #return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function links($order = 'asc')
{
return $this->morphMany(Link::class, 'linkable')->orderBy('order', $order);
}
/**
* Get profile theme.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function theme()
{
return $this->belongsTo(Theme::class);
}
/**
*
*/
public function viewed()
{
$this->increment('views');
}
/**
*
*/
public function registerMediaCollections()
{
$this->addMediaCollection('avatar')->singleFile();
}
/**
* #param Media|null $media
*
* #throws \Spatie\Image\Exceptions\InvalidManipulation
*/
public function registerMediaConversions(Media $media = null)
{
$this->addMediaConversion('cropped')
->crop(Manipulations::CROP_CENTER, 200, 200)
->nonQueued()
->performOnCollections('avatar');
}
}
Anyone know any method to do this so I can save storage space?

Laravel Nova doesn't find some Models

With some Models, when I make a new Nova Resource for them, seems that Nova can't find the Model because they doesn't show on sidebar (i can't reach them also by URL, giving me a 404).
But this happens only for specific Models and if I try to modify the target Model in the Resource with another one (editing the $model variable), it works and shows the Resource in the sidebar (but with the wrong model). Nova isn't throwing me any error so the debugging is getting crazy difficult.
The Models that doesn't work in my project are named "Product" and "Company".
I'm using Laravel 7.28.3, Nova 3.9.1, MariaDB 10.4.11 and PHP 7.4.1 with Homestead.
Here's the code of Product resource:
<?php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Http\Requests\NovaRequest;
class Product extends Resource
{
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = \App\Product::class;
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'title';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id', 'name'
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
And here's the Model code:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Product extends Model implements HasMedia
{
use InteractsWithMedia;
public function visits()
{
return visits($this);
}
public function user() {
return $this->belongsTo('App\User');
}
public function company() {
return $this->belongsTo('App\Company');
}
public function productVariety() {
return $this->belongsTo('App\ProductVariety', 'product_variety_id');
}
public function productSpecies() {
return $this->belongsTo('App\ProductSpecies', 'product_species_id');
}
public function productNutrients() {
return $this->hasMany('App\ProductNutrient');
}
public function baseProduct() {
return $this->hasOne('App\Product', 'base_product_id');
}
public function recipes() {
return $this->hasMany('App\Recipe', 'base_product_id');
}
protected $fillable = [
'user_id', 'company_id', 'imageline_id', 'products_species_id', 'products_varieties_id', 'base_product_id',
'name', 'scientific_name', 'production_start', 'production_end', 'production_city', 'description', 'story', 'curiosities', 'advices', 'quantity_advices', 'why_good', 'who_good',
'is_base_product', 'show_related_recipes', 'show_related_products'
];
}
Check your AuthServiceProvider on app/Providers/AuthServiceProvider.php if there is a Policy set to this model. Then on your policy class (probably ProductPolicy which is bind to Product model, check view and viewAny methods, these methods must return true or conditional true.

Traversing Doctrine2 ODM/MongoDB Object Graph in Symfony2 fails to populate properties in 2nd level object

I am converting my otherwise working Symfony2 application to use MongoDB through Doctrine-ODM. I have the vast majority of the system working, but I can't get the user roles portion working. I can login, but then there are no roles attached to the user.
The relevant document classes are here with everything stripped out except what is relevant.
User
<?php
namespace XXXXX\UserBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\Common\Collections\ArrayCollection;
use XXXXX\UserBundle\Interfaces\UserInterface;
/**
*
* #MongoDB\Document( collection="user")
*
*/
class User implements UserInterface {
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\ReferenceMany(targetDocument="Group")
*/
protected $groups;
/**
* Constructor
*/
public function __construct() {
$this->groups = new ArrayCollection();
$this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
}
public function getRoles() {
$array = array();
//parse the roles down to an array
foreach ($this->getGroups() as $group) {
/* #var $group Group */
foreach ($group->getRoles() as $role) {
/* #var $role Role */
if(!$role->getName())
throw new \Exception('Role must exist in group: '.$group->getName().' with ID: '.$group->getId().'.');
$array[$role->getName()] = $role->getName();
}
}
sort($array);
return $array;
}
/**
* Get groups
*
* #return Doctrine\Common\Collections\Collection
*/
public function getGroups() {
return $this->groups;
}
}
Group
<?php
namespace XXXXX\UserBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use XXXXX\UserBundle\Interfaces\UserInterface;
use XXXXX\UserBundle\Interfaces\RoleInterface;
use XXXXX\UserBundle\Interfaces\GroupInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #MongoDB\Document( collection="user_group" )
*/
class Group implements GroupInterface {
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\String
* #var string
*/
protected $name;
/**
* #MongoDB\ReferenceMany(targetDocument="User")
*/
protected $users;
/**
* #MongoDB\ReferenceMany(targetDocument="Role", inversedBy="groups")
*/
protected $roles;
/**
* Constructor
*/
public function __construct() {
$this->users = new ArrayCollection();
$this->roles = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get roles
*
* #return Doctrine\Common\Collections\Collection
*/
public function getRoles()
{
return $this->roles;
}
}
Role
<?php
namespace XXXXX\UserBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use XXXXX\UserBundle\Interfaces\UserInterface;
use XXXXX\UserBundle\Interfaces\GroupInterface;
use XXXXX\UserBundle\Interfaces\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #MongoDB\Document( collection="user_role")
*/
class Role implements RoleInterface {
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\String
* #var string
*/
protected $name;
/**
* #MongoDB\String
* #var string
*/
protected $description;
/**
* #MongoDB\ReferenceMany(targetDocument="Group", mappedBy="roles")
*/
protected $groups;
/**
* Set name
*
* #param string $name
* #return RoleInterface
*/
public function setName($name) {
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName() {
return $this->name;
}
public function getId() {
return $this->id;
}
public function getDescription() {
return $this->description;
}
public function setDescription($description) {
$this->description = $description;
}
}
I use fixtures to load the data into the database, and the data in MongoDB is as follows. ( I stripped the additional data elements.)
User.
{ "_id" : ObjectId("5091a7241311fae01f00000d"), "groups" : [ DBRef("user_group", ObjectId("5091a7241311fae01f00000b")), DBRef("user_group", ObjectId("5091a7241311fae01f00000c")) ] }
Groups that are referenced by the User. (This is from the query that is run by Symfony2)
db.user_group.find({ "_id": { "$in": { "5091a7241311fae01f00000b":ObjectId("5091a7241311fae01f00000b"), "5091a7241311fae01f00000c": ObjectId("5091a7241311fae01f00000c") } } }).sort([ ]);
{ "_id" : ObjectId("5091a7241311fae01f00000b"), "name" : "Base.Users", "roles" : [ DBRef("user_role", ObjectId("5091a7241311fae01f000009")) ] }
{ "_id" : ObjectId("5091a7241311fae01f00000c"), "name" : "AdminPortal.Base", "roles" : [ DBRef("user_role", ObjectId("5091a7241311fae01f000009")), DBRef("user_role", ObjectId("5091a7241311fae01f00000a")) ] }
And finally, the roles referenced by the groups. (Also taken from the exact query being run by Symfony2)
db.user_role.find({ "_id": { "$in": { "5091a7241311fae01f000009": ObjectId("5091a7241311fae01f000009") } } }).sort([ ]);
{ "_id" : ObjectId("5091a7241311fae01f000009"), "name" : "ROLE_USER", "description" : "Role required for all system users." }
Further, the exception in the getRoles() function for the user is called and the following text is returned.
Role must exist in group: Base.Users with ID:
5091a7241311fae01f00000b.
The problem is that the roles are being queried from the database, but are not then being populated into the role object. I can verify that they are being loaded, as when I comment the exception, it will run and attempt to add the correct number of roles per group. The problem is that the name property of the role is set to NULL. The role object itself is a persisted and loaded object as when I do a print_r($role);exit; directly before the if statement, I will get the hugely recursive output that doctrine objects exhibit. The only thing that doesn't happen is that the "name" (and other) properties are not loaded from the database.
Any insight into how I can solve this would be greatly appreciated. Thanks.
I was able to determine a work-around. Basically, using the convientent functions like find, findBy, findOneBy, etc do not seem to be setting the objects up for traversing. I was able to get the correct result by modifying the loading function to use a querybuilder instead of the convenient function "findOneBy".
My modified query is below. Hopefully this helps somebody in the future.
/**
*
* #param string $username
* #return User|Null
*/
public function findUserByUserName($username) {
$qb = $this->createQueryBuilder();
$qb->find($this->getClassName());
$qb->field('username');
$qb->equals($username);
$query = $qb->getQuery();
return $query->getSingleResult();
}
I suppose it could be more concise, but I had to break it apart to debug it, and am moving on with my life. :)

Categories