I need to make a raw database query using Laravel:
$results = DB::select("SELECT * FROM members
INNER JOIN (several other tables)
WHERE (horribly complicated thing)
LIMIT 1");
I get back a plain PHP StdClass Object with fields for the properties on the members table. I'd like to convert that to a Member (an Eloquent model instance), which looks like this:
use Illuminate\Database\Eloquent\Model;
class Member extends Model {
}
I'm not sure how to do it since a Member doesn't have any fields set on it, and I'm worried I will not initialize it properly. What is the best way to achieve that?
You can try to hydrate your results to Model objects:
$results = DB::select("SELECT * FROM members
INNER JOIN (several other tables)
WHERE (horribly complicated thing)
LIMIT 1");
$models = Member::hydrate( $results->toArray() );
Or you can even let Laravel auto-hydrate them for you from the raw query:
$models = Member::hydrateRaw( "SELECT * FROM members...");
EDIT
From Laravel 5.4 hydrateRaw is no more available. We can use fromQuery instead:
$models = Member::fromQuery( "SELECT * FROM members...");
You can simply init a new model:
$member = new App\Member;
Then you can assign the columns:
$member->column = '';
Or if all columns are mass assignable:
$member->fill((array)$results);
Or have I misunderstood something?
You should definetly use Eloquent to perform that.
You might declare the relations between the models, and use the where conditions.
like:
Member::where(......)->get();
This will return an eloquent instance, and you can do whatever you need.
Related
Good day, please, for some reasons I have to use query builder instead of Eloquent, the reason been that the name of my model is KidsCafe and if I use Eloquent, it will search for a table with myapp.kidscaves, but the name of the table is kidscafes this is throwing errors, so I have to use query builder in my interaction with the db.
Now, I have to implement search functionality, so how do I implement something like this using query builder
$kids = KidsCafe::query();
My question is how do I implement query(); using query builder, and also is there another way I can use eloquent without it
thank you in advance
You can manually specify a table name by defining a table property on your model:
class KidsCafe extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'kidscafes';
}
You can also use the setTable() function do dynamically use another table's name, something like this -
$kidscafes = new KidsCafe;
$kidscafes->setTable('kidscafes');
I'm working with Laravel and Nova. So basically in Laravel, I have a model like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
}
Then, Nova helps me create a nice CMS web interface at https://example.com/admin/resouces/flights that lists all my flights and https://example.com/admin/resouces/flights/<id> to let me CRUD against a particular record. All I have to do to make this happen is create the file app/Nova/Flight.php with the content:
<?php
namespace App\Nova;
//... import other classes like Text Fields, WYSIWYG editors etc.. etc.., that are the nice CMS UI fields to modify each column in my flights table
class Flight extends Resource
{
public static $model = 'App\Flight';
// ... list of fields I want to modify ...
}
This works fine and all, except now I want to make two different urls like:
* `https://example.com/admin/resouces/flights-cancelled` - this should only list the equivalent of `SELECT * FROM flights WHERE status = 'cancelled'`
* `https://example.com/admin/resouces/flights-active` - this should only list the equivalent of `SELECT * FROM flights WHERE status = 'active'`
Things will get a bit more complicated as my project evolves, so I was wondering if there's a way to define a new model called App\FlightCancelled that is exactly the same as App\Flight, except all queries to the database will always include a WHERE status='cancelled' condition. That way I can assign App\FlightCancelled as the model to my Nova resource.
Curious how that's done? Or if there's a better way to achieve my objective?
You can modify $table and override newQuery() - the method that Eloquent use to construct a new query.
FlightCancelled
protected $table = 'flights'
public function newQuery($excludeDeleted = true)
{
return parent::newQuery($excludeDeleted)
->where('status', '=', 'cancelled');
}
In this case, I recommend using lenses, allow you to fully customize the underlying resource Eloquent query.
class FlightCancelled extends Lens
{
public static function query(LensRequest $request, $query)
{
// Query here..
}
//
}
I kept searching the web for an hour but couldn't figure this out. If we look at the eloquent relationships documentation:
https://laravel.com/docs/5.2/eloquent-relationships
The example User model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('App\Phone');
}
}
Just below it, how to access the phone number of a user with id=1:
$phone = User::find(1)->phone;
Why is it phone and not phone() and what is the difference?
Also how does it work? If I try to call an object->name without parenthesis in my code PHP thinks I am looking for a class variable named name?
Some extra information:
It looks like phone is returning object(App\Models\Phone) and phone() is returning object(Illuminate\Database\Eloquent\Relations\HasOne)
If I run the code below:
User::find(1)->phone->count()
Framework executes following SQL statements:
select * from `phone` where `phone`.`user_id` = '1' and `phone`.`user_id` is not null limit 1
select count(*) as aggregate from `phone`
If I run the code below:
User::find(1)->phone()->count()
Framework executes following SQL statement:
select count(*) as aggregate from `phone` where `phone`.`user_id` = '1' and `phone`.`user_id` is not null
One way of thinking about it is that the public function phone() function defines the relationship, so using $obj->phone() would get you the Eloquent relationship itself (not the results of that relationship) which you could then modify with various query builder elements if you wanted.
Leaving out the brackets is the Eloquent shorthand for adding ->get() or ->first() at the end of the expression (Eloquent knows which to use based on if it's a hasOne, hasMany, etc. relationship, as defined in the function), which returns an Eloquent collection.
So, $obj->phone is the same as $obj->phone()->first().
I don't know Laravel/Eloquent and you would need to show the find() method for more information, but User::find(1) returns an object so the ->phone accesses the phone property of that object. This has nothing to do with the find() method that you have shown. It is shorter than this that would do the same:
$obj = User::find(1);
$phone = $obj->phone;
Do a var_dump($obj); and you should see a phone property. If not, then another possibility is that the class implements a __get() magic method so that when you attempt to access the phone property it runs the phone() method and returns the value.
As for the first explanation, the same can be done with arrays:
function test() { return array('phone'=>'713-555-1212'); }
echo test()['phone'];
In my system users can have many timesheets, timesheets can have many data.
I'm trying to update the data rows in the data_timesheet table. I'm using this:
$data = ['column_1' => 'value'];
$this->findTimesheetById($id)->data()->saveMany($data);
However, it's giving me the following error:
Argument 1 passed to Illuminate\Database\Eloquent\Relations\HasOneOrMany::save() must be an instance of Illuminate\Database\Eloquent\Model, array given
I know why it's giving me the error, because I need to send it a model as opposed to an array. How can I send in a model, when the values being passed are from a user form?
EDIT:
I can do this which works, but there must be a better way?
$data = $this->findTimesheetById($id)->data();
$data->delete();
$data->insert($data);
The way to do that is:
1) You create a file model and put it in the Models folder. That model can even almost empty, like this:
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Session;
use DB;
class Booking extends Model{
2) Then in the Controller you create an instance of that Model, like this
$theinstance = new Booking;
3) Then you use that object to have the values given, like this:
$theinstance->name = $name;
$theinstance->telephone = $telephone;
$theinstance->save();
That would be the way to save data.
Now, with regards to the update, at the Controller you can have something like this:
$photosslide = Property::returnPhotosSlide($id);
$propertydetails = Property::returnPropertyDetails($id);
$alsointown = Property::returnAlsoInTown($id);
return view('detailsproperty', compact('photosslide','propertydetails','alsointown'));
This sends the values from a Form into the Model
and once you are in the Model, just do an Update query.
Situation:
There is simple User class which is Doctrine entity (I skipped comments to keep the code short):
class User {
protected $iUserId;
protected $sName;
}
Question:
How to retrieve collection of objects of class User from the controller?
Follow up:
Until now, we were creating methods like getUsers() in User class which gets data from DB, creates User class objects and returns it.
Now, I'm wondering if it's not a better solution to create class like UserCollection which would handle data retrieving and creating User objects? Maybe I should make use of \Doctrine\Common\Collections\Collection class somehow?
What I'd like to accomplish is easy way to handles i.e. where clauses. UserCollection class could have QueryBuilder object on which I could operate from controller like this:
$oUserCollection = new UserCollection();
$oUserCollection->setWhere( 'u.iUserId = 1' );
$aUsers = oUserCollection->getUsers();
...
Please share your thoughts on that topic.
Update:
Doctrine provides a concept of repositories of entities which I think maybe the solution I'm looking for.
You have two options:
If your criterias are simple, eg. you just want to filter on a single property, or you don't need filtering at all, you can use the findBy() and findAll() methods, on the EntityRepository:
// find all users
$repository = $em->getRepository('My\\User');
$users = $repository->findAll();
// find users who are marked as active
$users = $repository->findBy(array('active' => true));
// sort users by age
$users = $repository->findBy(array(), array('age' => 'DESC'));
If you have complex(er) requirements, or your finders will be used from multiple places, you will have to create a custom EntityRepository, and group your finder logic there. You have to specify in the mapping that you want to create your own EntityRepository for this entity, the method for this varies depending on what mapping driver you use (annotation, yaml, xml). For example, in yaml you would have to place this line in your mapping:
RepositoryClass: My\Repository\UserRepository
And then create the file:
namespace My\Repository;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository {
public function findVIPUsers() {
$query = $this->_em->createQuery("Your query here");
return $query->getResult();
// you can also use $this->findBy(), or $this->findAll() here
}
}
And then in your controller, when you call $em->getRepository('My\User') it will return the custom repository you just created.