Laravel/PHP: New Instance of Model Class within Method of This Model - php

New to Laravel and still fresh to OOP! I'm assuming this has more to do with OOP than strictly Laravel.
So my main problem is that I am trying to pass all rows from a database table called 'fin_income_category' via a method in my model called Income to a controller called PlannerController. To do this I have created a static method within Income called getIncomeCategories()
First of all, here is my __construct method within Income:
public function __construct($income, array $attributes = array()){
parent::__construct($attributes);
$this->table = $income;
}
And here is the getIncomeCategories method also within Income:
public static function getIncomeCategories(){
$category = new self('fin_income_category');
$categories = $category->all();
return $categories;
}
Finally, here is the edit($id) method within the PlannerController where I am to call this method and pass the categories along to my view. Note that only the first statement in this function is the one in question...the others work fine:
public function edit($id)
{
$income_categories = Income::getIncomeCategories();
$newIncome = new Income('fin_income');
$newRecord = $newIncome->where('id', '=', $id)->get();
return View::make('planner.edit', array('record'=>$newRecord, 'categories'=>$income_categories));
}
When I run the code like this I receive an error from Laravel:
ErrorException
Missing argument 1 for Income::__construct(),
called in /opt/lampstack/frameworks/laravel/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 615 and defined
In other cases where I have instantiated a new Income I have not received this error.

Change the getIncomeCategories() to this
public static function getIncomeCategories(){
$category = new self('fin_income_category');
return $category->get()->toArray();
}
The reason why your code didn't work is because the eloquent all() found in
Illuminate\Database\Eloquent\Model; the code snippet is found below
public static function all($columns = array('*'))
{
$instance = new static;
return $instance->newQuery()->get($columns);
}
is instantiating a static class which is bound to the called class which is your Income Model Class in your case, and in the process requesting the arguments in the constructor

Related

Laravel attach returns undefined method for belongsToMany relationship

I would like to create a question which has many surveys. In the questions Model:
public function surveys()
{
return $this->belongsToMany(Survey::class, 'survey__surveyquestions');
}
And in the controller when saving a new question:
private $questions;
public function __construct(QuestionsRepository $questions)
{
parent::__construct();
$this->questions = $questions;
}
public function store(Request $request)
{
$this->questions->create($request->all());
$this->questions->surveys()->attach($request->surveys);
return redirect()->route('admin.survey.questions.index')
->withSuccess(trans('core::core.messages.resource created', ['name' => trans('survey::questions.title.questions')]));
}
But I get the following error when it gets to the attach line:
(1/1) FatalErrorException Call to undefined method
Modules\Survey\Repositories\Eloquent\EloquentQuestionsRepository::surveys()
I notice the error mentions EloquentQuestionsRepository but I have added no methods in there so it's just an empty class:
class EloquentQuestionsRepository extends EloquentBaseRepository implements QuestionsRepository
{
}
QuestionRepository:
interface QuestionsRepository extends BaseRepository
{
}
As explained in the response to the main post - the constructor resolves the QuestionsRepository to instance of EloquentQuestionsRepository, which by the look of it is not what the store method needs.
What I would probably do is to make call to create method directly on the model and remove constructor all together - that is unless you need the instance of QuestionsRepository anywhere else in your controller:
public function store(Request $request)
{
$question = Question::create($request->all());
$question->surveys()->attach($request->surveys);
...
}
Also - I'm not sure passing $request->all() is the best thing to do - I'd probably use $request->only(...) or $request->all(...) specifying which items you want to get from the request rather than passing everything from the request to the create method.
On the other note - you could also use Form Request, which would validate data for your before passing it to the store method.
https://laravel.com/docs/5.5/validation#form-request-validation

Call to a member function getPaginate() on a non-object

I'm new to laravel framwork , and I'm coding my first web app
and getting the following error
FatalErrorException in PersonController.php line 26:
Call to a member function getPaginate() on a non-object
this is my Controller
<?php
namespace App\Http\Controllers;
use App\Repositories\PersonRepository;
class PersonController extends Controller
{
protected $personRepo ;
protected $nbrPerPage = 4 ;
public function _construct(PersonRepository $personRepository)
{
$this->personRepo = $personRepository ;
}
public function index()
{
$persons = $this->personRepo->getPaginate(nbrPerPage);
$links = $persons->setPath('')->render();
return view('index', compact('persons', 'links'));
}
public function create()
{
}
public function store()
{
}
public function show($id)
{
//
}
public function edit($id)
{
//
}
public function update($id)
{
//
}
public function destroy($id)
{
//
}
}
and this my repository class
<?php
namespace App\Repositories ;
use App\Person ;
use App\User;
class PersonRepository {
protected $person ;
public function _construct (Person $person)
{
$this->$person = $person ;
}
public function getPaginate($n)
{
return $this->person-> paginate($n) ;
}
}
You are instantiating an empty instance of the Person model and then trying to call paginate() on it in your repository. However, paginate() is meant to be called on either a query builder object or an Eloquent query. Assuming that you want to return paginated results of all your models, you can scrap the $person property entirely as well as the constructor and then just change your method to this:
public function getPaginate($n)
{
return Person::paginate($n) ;
}
I will say that for such a simple query, I would suggest not using a repository altogether and just use Person::paginate($n) inside your controller, as Eloquent essentially functions as a repository already.
Unless these are just typos in the question, you have a lot of typos in your code.
The typo that is causing this specific error is that the name of the constructor method should be __construct (with two underscores), not _construct (with one underscore).
Since the constructor method is misspelled on your PersonController, this method is never called and the personRepo attribute is never set. Since it is never set, the line $persons = $this->personRepo->getPaginate(nbrPerPage); is trying to call getPaginate() on a non-object.
Additional typos/issues I see at a glance:
$persons = $this->personRepo->getPaginate(nbrPerPage);
nbrPerPage is being used as a constant. This is incorrect. Should be:
$persons = $this->personRepo->getPaginate($this->nbrPerPage);
Constructor on PersonRepository also misspelled. Should be __construct(), not _construct.
$this->$person = $person ;
This is inside the attempted construct of the PersonRepository. The $ needs to be removed from $this->$person. Should be:
$this->person = $person;

Yii ActiveRecord model save by chain

There is a model:
class Model extends ActiveRecord
{
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function toSave(Array $data)
{
$this->setAttributes($data);
$this->save(); // returns true
return $this;
}
}
and running
$model = Model::model()->toSave($data);
and when im dumping $model there is all data which setted from $data but not exists PrimaryKey (id).
but, if i run
$model = new Model;
$model->toSave($data);
works as expected.
Where is a problem?
you are doing multiple save, through iterating, and pass new set of $data everytime. $model here is an object of single record. So by doing everytime, new model , you are creating fresh new object, assign data and save. Later you did is the right approach.
You usage in invalid in the first instance
$model = Model::model()->toSave($data);
In this case, the usage is calling the toSave() method statically.
First, the usage is illegal unless you change your declaration
public static function toSave(Array $data) { ... }
In addition, when invoked statically, the value for $this is invalid.
Therefore, the valid usage is your second version:
$model = new Model;
$model->toSave($data);
References:
http://php.net/manual/en/language.oop5.static.php

Laravel 5 Eager Loading not working

I look at many search results with this trouble but i can`t get it to work.
The User Model:
<?php namespace Module\Core\Models;
class User extends Model {
(...)
protected function Person() {
return $this->belongsTo( 'Module\Core\Models\Person', 'person_id' );
}
(...)
And the Person Model:
<?php namespace Module\Core\Models;
class Person extends Model {
(...)
protected function User(){
return $this->hasOne('Module\Core\Models\User', 'person_id');
}
(...)
Now, if i use User::find(1)->Person->first_name its work. I can get the Persons relations from the User Model.
But.. User::with('Person')->get() fails with a Call to undefined method Illuminate\Database\Query\Builder::Person()
What im doing wrong? i need a collection of all the users with their Person information.
You have to declare the relationship methods as public.
Why is that? Let's take a look at the with() method:
public static function with($relations)
{
if (is_string($relations)) $relations = func_get_args();
$instance = new static;
return $instance->newQuery()->with($relations);
}
Since the method is called from a static context it can't just call $this->Person(). Instead it creates a new instance of the model and creates a query builder instance and calls with on that and so on. In the end the relationship method has to be accessible from outside the model. That's why the visibility needs to be public.

Non-Static Method should not be called Statically

I am using a repository pattern and am trying to establish relationships between models. When I try to run the store() method (in the controller) which is trying to use the user() method (which establishes the relationship with the Party model), I get the following error message:
Non-static method Party::user() should not be called statically, assuming $this from incompatible context
I don't understand why I get this error when I try to run the user() relationship method, but all of the other methods (including $this->party->all(), $this->party->create($data)), work just fine.
Here is the relevant code:
// PartiesController.php
public function __construct(Party $party){
$this->party = $party
}
public function store(){
$data = Input::all();
$user = Sentry::getUser();
$this->party->user()->create($data);
}
// Party.php
class Party extends Eloquent{
public function user(){
return $this->belongsTo('User');
}
}
// User.php
use Cartalyst\Sentry\Users\Eloquent\User as SentryUserModel;
class User extends SentryUserModel implements UserInterface, RemindableInterface {
public function party(){
return $this->hasMany('Party');
}
}
// PartyRepository.php
namespace repositories\Party;
interface PartyRepository{
public function all();
public function findByID($id);
public function create($input);
public function user();
}
// EloquentPartyRepository.php
namespace repositories\Party;
use Party;
class EloquentPartyRepository implements PartyRepository{
public function all(){
return Party::all();
}
public function create($input){
return Party::create($input);
}
public function user(){
return Party::user();
}
}
The issue is because you are calling a non-static method in a static context. You may be used to seeing the way Laravel does a lot of this (e.g. User::find() and the like). These, in reality though, are not static calls (a class instance is actually being resolved behind the scenes and the find() method invoked on that instance).
In your case, it is just a plain static method call. PHP would allow this, except for the fact that in the method you are referencing $this and PHP doesn't know what to do with it. Static method calls, by definition, have no knowledge of any instances of a class.
My advice would be to inject an instance of your Model class into your repository's constructor, something like this:
//Class: EloquentPartyRepository
public function __construct(Party $party)
{
$this->party = $party;
}
public function user($partyId)
{
return $this->party->find($partyId)->user();
}
The Party instance you send to the constructor should not be a record from the database, just an empty instance of Party (i.e. new Party()), though I believe if you just add it to the constructor, the IoC should be able to leverage dependency injection and provide you with an instance.
An equivalent implementation is here, that adds a byId method:
//Class: EloquentPartyRepository
public function __construct(Party $party)
{
$this->party = $party;
}
public function byId($partyId)
{
return $this->party->find($partyId);
}
public function user($partyId)
{
if($party = $this->byId($partyId)) {
return $party->user();
}
return null;
}
I have solved the problem. Thank you #watcher and #deczo for your feedback. Both were very helpful and relevant to this error message.
In the end, I only needed to change one line. I had the sequence of method calls out of order in the store() function. Here is the relevant code.
// PartiesController.php
public function store(){
$data = Input::all();
$user = Sentry::getUser();
$user->party()->create($data);
}
In my case, to remove the non-static error and to properly insert the User model into the Party model, I only had to make the aforementioned change.
I referred to http://laravel.com/docs/eloquent/#inserting-related-models for the appropriate sequence.

Categories