Every time I try to instantiate a certain model and use it, like for example:
$categories = Model::factory('category')->by_sale($id)->find_all();
I get a weird error. If i have i bootstrap in kohana::init set 'errors' => TRUE,the error is: Could not execute Model_Category::__construct() else i get only a warning Warning: array_keys() expects parameter 1 to be array, null given in /application/classes/model.php on line 42
meaning here:
private function _get_real_property_name($property)
{
if (isset($this->_belongs_to[$property]) OR
isset($this->_has_one[$property]) OR
isset($this->_has_many[$property]))
return $property;
$column_prefix = $this->_table_name . '_';
$property_prefix = substr($property, 0, strlen($column_prefix));
if ($property_prefix != $column_prefix)
{
$prefixed_property = $column_prefix . $property;
if (in_array($prefixed_property, array_keys($this->table_columns())))
{
return $prefixed_property;
}
}
return $property;
}
The category model looks like this:
class Model_Category extends Model {
/**
* #see ORM::_table_name
*
* #var array
*/
protected $_table_name = 'category';
/**
* #see ORM::_primary_key
*
* #var array
*/
protected $_primary_key = 'category_id';
/**
* #see ORM::_belongs_to
*
* #var array
*/
protected $_belongs_to = array(
'parent' => array('model' => 'category', 'foreign_key' => 'category_category'),
'sale' => array('foreign_key' => 'category_sale')
);
/**
* #see ORM::_has_many
*
* #var array
*/
protected $_has_many = array(
'products' => array('model' => 'product', 'foreign_key' => 'product_category')
);
/**
* Adds the 'top_level' condition to the query
*
* #return Model_Sale
*/
public function top_level()
{
return $this->where('category_category', '=', 0);
}
/**
* Adds the 'by_sale' condition to the query
*
* #return Model_Sale
*/
public function by_sale($sale_id)
{
return $this->where('category_sale', '=', $sale_id);
}
public function __get($property)
{
if ($property == 'siblings')
{
return $this->where('category_sale', '=', $this->sale->id)
->where('category_category', '=', $this->category_category);
}
if ($property == 'children')
{
return $this->where('category_category', '=', $this->pk());
}
return parent::__get($property);
}
} // End Model_Category
Thank you!
I don't recognize the $this->table_columns(). When looking at http://kohanaframework.org/3.0/guide/api/Model I don't see it there either.
Have you added this method to the Model class yourself? I'm guessing it's not returning the proper type.
I am not familiar with Kohana, but it is quite resembling with Codeigniter. You can try this in your model that extends model class:
function __construct(){
parent::Model();
}
(eventually pass the parameters that you have)
Try replacing $this->table_columns() by $this->table_columns (in _get_real_property_name()) because table_columns seems to be a variable, not a method :3
Related
I have 2 entities, document and field, inside entities I have some relation OneToMany and ManyToOne..
I'm troubled cause when I try to get values of fields from document in the controller. I get error cause I can't use methode on string.
to resume:
part of document.php:
/**
* #var ArrayCollection $fields
*
* #ORM\OneToMany(targetEntity="AUTOFUSION\AutofusionBundle\Entity\Field", mappedBy="document", cascade={"persist", "remove", "merge"})
*/
private $fields;
/**
* Constructor
*/
public function __construct()
{
$this->fields = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add field
*
* #param \AUTOFUSION\Autofusionbundle\Entity\Field $field
*
* #return Document
*/
public function addField(\AUTOFUSION\AutofusionBundle\Entity\Field $field)
{
$this->fields[] = $field;
return $this;
}
/**
* Remove field
*
* #param \AUTOFUSION\AutofusionBundle\Entity\Field $field
*/
public function removeField(\AUTOFUSION\AutofusionBundle\Entity\Field $field)
{
$this->fields->removeElement($field);
}
/**
* Get fields
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getFields()
{
return $this->fields;
}
Part of DefaultController.php:
public function indexAction{
$regroupings = $em->getRepository('AUTOFUSIONAutofusionBundle:Regrouping')->FindRegrouping();
}
public function DocumentsArray($regroupings){
$i=0;
foreach($regroupings as $regrouping){
foreach($regrouping->getDocuments() as $document){
foreach($document->getFields() as $fields){
var_dump($document->getFields());
die();
//$documents[$i] = $document->getFields()->getValue();
}
$i++;
}
return $documents;
}
}
Part of Repository:
public function FindRegrouping(){
return $this->_em->createQueryBuilder()
->select('p','gdt','dt','d','f')
->from('AUTOFUSION\AutofusionBundle\Entity\Regrouping', 'p')
->leftJoin('p.groupDocType', 'gdt')
->leftJoin('p.documents','d')
->leftJoin('d.docType', 'dt')
->leftJoin('d.fields', 'f')
//->where('v.cp=:cp')
//->setParameter('cp', $cp);
->getQuery()
->getResult();
}
here part of the output var_dump($document->getFields());:
protected 'collection' =>
object(Doctrine\Common\Collections\ArrayCollection)[590]
private 'elements' =>
array (size=4)
0 => string 'NOM_CLIENT' (length=10)
1 =>
object(AUTOFUSION\AutofusionBundle\Entity\Field)[599]
...
2 =>
object(AUTOFUSION\AutofusionBundle\Entity\Field)[600]
...
3 =>
object(AUTOFUSION\AutofusionBundle\Entity\Field)[601]
...
So, I don't understant why the first item of arraycollection is a string?!
Look at my code. When you iterate over getFields(), there is no need to call it again inside loop. getFields() returns array, so when you're not trying to treat it as array, it can behave different. In this case, it tried to be a string.
PS - you don't need $i counter in your code.
foreach($document->getFields() as $field){
var_dump($field);
$documents[] = $field->getValue();
}
Right now I try this query with eloquent:
'MentorId' => $employee->intern(true)->mentor(true)->MentorId,
And in my employee and intern model I've got this:
Intern
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo(internModel::class, 'InternId')->withTrashed();
}
return $this->belongsTo(internModel::class,'InternId');
}
Mentor
/**
* #return mixed
*/
public function mentor($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo(mentorModel::class, 'MentorId')->withTrashed();
}
return $this->belongsTo(mentorModel::class,'MentorId');
}
But it crashes:
BadMethodCallException in Builder.php line 2148:
Call to undefined method Illuminate\Database\Query\Builder::mentor()
How could I fix this?
--EDIT--
Employee
<?php
namespace App\src\employee;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\src\department\Department as departmentModel;
use App\src\employee\Employee as employeeModel;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\src\intern\Intern as internModel;
use App\src\mentor\Mentor as mentorModel;
use App\src\employee\Role as roleModel;
class Employee extends Authenticatable
{
use SoftDeletes;
use EmployeeServiceTrait;
/**
* table name
*/
protected $table = 'employee';
/**
* Mass assignment fields
*/
protected $fillable = ['RoleId', 'DepartmentId', 'InternId', 'FirstName', 'LastName', 'Bio','api_token', 'email', 'LinkedIn', 'password', 'Address', 'Zip', 'City', 'ProfilePicture', 'BirthDate', 'StartDate', 'EndDate', 'Suspended','LinkedIn'];
/**
* Primarykey
*/
protected $primaryKey = 'EmployeeId';
/**
* Deleted_at
*/
protected $dates = ['deleted_at'];
/**
* #return mixed
*/
public function role()
{
return $this->belongsTo(roleModel::class,'RoleId');
}
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo(internModel::class, 'InternId')->withTrashed();
}
return $this->belongsTo(internModel::class,'InternId');
}
/**
* #return mixed
*/
public function department()
{
return $this->belongsTo(departmentModel::class,'DepartmentId');
}
/**
* #return mixed
*/
public function mentor()
{
return $this->belongsTo(mentorModel::class,'MentorId');
}
/**
* #return mixed
*/
public function employees()
{
return $this->hasManyThrough(employeeModel::class,departmentModel::class,'CompanyId','DepartmentId');
}
/**
* #param $role
* #return bool
*/
public function hasRole($role)
{
if(strtolower($this->role->RoleName) == strtolower($role))
{
return true;
}
return false;
}
}
The problem you have is that any Eloquent relationship object is actually an instance of Relation. This means when you create relationships you actually return a collection (instance of Builder); Hense your error:
BadMethodCallException in Builder.php line 2148:
Call to undefined method Illuminate\Database\Query\Builder::mentor()
The simple solution, without any modification to your code would be something like:
'MentorId' => $employee->intern(true)->first()->mentor(true)->first()->MentorId;
However, you could use overloading like the following:
'MentorId' => $employee->intern->mentor->MentorId;
Although this will NOT include your withTrashed. You can however tweak your relationship to something like:
public function intern($withTrashed = false)
{
$relation = $this->belongsTo(internModel::class, 'InternId');
if($withTrashed == true)
{
return $relation->withTrashed()->first();
}
return $relation->first();
}
But I wouldn't advise this because later on if you try using things like WhereHas you will get errors. That said, another way would be to do something along the following lines:
public function intern()
{
return $this->belongsTo(internModel::class, 'InternId');
}
Then get trashed like:
'MentorId' => $employee->intern()->withTrashed()->first()->mentor()->withTrashed()->first()->MentorId;
Try as below as per laravel guide. Keep in mind that parent model must have hasOne/hasMany method and child model must have belongsTo method.
Intern
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->hasOne('App\Intern', 'InternId')->withTrashed();
}
return $this->hasOne('App\Intern','InternId');
}
Employee
/**
* #return mixed
*/
public function intern($withTrashed = false)
{
if($withTrashed == true)
{
return $this->belongsTo('App\Intern', 'InternId')->withTrashed();
}
return $this->belongsTo('App\Intern','InternId');
}
Note: Same for all other models.
I am learning phalcon. I have some problems with models.
Function FindFirst returns nothing, also it doesn't show any errors or exceptions. Here is my code:
public function indexAction()
{
$user = Users::findFirst(1);
var_dump($user);
}
And all what I get - is empty page.
Here is my Users Model:
<?php
namespace Models\User;
use Phalcon\Mvc\Model\Validator\Email as Email;
class Users extends \Phalcon\Mvc\Model
{
/**
*
* #var integer
*/
public $id;
/**
*
* #var string
*/
public $login;
/**
*
* #var string
*/
public $email;
public function initialize()
{
$this->setSource("users");
}
/**
* Validations and business logic
*/
public function validation()
{
$this->validate(
new Email(
array(
'field' => 'email',
'required' => true,
)
)
);
if ($this->validationHasFailed() == true) {
return false;
}
}
/**
* Independent Column Mapping.
* Keys are the real names in the table and the values their names in the application
*
* #return array
*/
public function columnMap()
{
return array(
'id' => 'id',
'login' => 'login',
'email' => 'email'
);
}
}
Some additional information:
I have edited config files.
Phalcon version is 2.0
First you should ensure that the User model you are trying to load is in the right namespace, what means in your case you should use:
$user = \Models\User\Users::findFirst(1);
And to retrieve an output (depending on your index.php but probably this way) you should return "something", otherwise the buffer will be empty and nothing will be displayed.
i'm trying to test a simple class. I'm following this tutorial( http://code.tutsplus.com/tutorials/testing-laravel-controllers--net-31456 ).
I have this error, while running tests:
Method Mockery_0_App_Interfaces_MealTypeRepositoryInterface::getValidator() does not exist on this mock object
Im using repository structure. So, my controller calls repository and that returns Eloquent's response.
I'm relatively new in php and laravel. And I've started learning to test a few days ago, so I'm sorry for that messy code.
My test case:
class MealTypeControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('App\Interfaces\MealTypeRepositoryInterface');
$this->app->instance('App\Interfaces\MealTypeRepositoryInterface' , $this->mock);
}
public function tearDown()
{
Mockery::close();
}
public function testIndex()
{
$this->mock
->shouldReceive('all')
->once()
->andReturn(['mealTypes' => (object)['id' => 1 , 'name' => 'jidlo']]);
$this->call('GET' , 'mealType');
$this->assertViewHas('mealTypes');
}
public function testStoreFails()
{
$input = ['name' => 'x'];
$this->mock
->shouldReceive('getValidator')
->once()
->andReturn(Mockery::mock(['fails' => true]));
$this->mock
->shouldReceive('create')
->once()
->with($input);
$this->call('POST' , 'mealType' , $input ); // this line throws the error
$this->assertRedirectedToRoute('mealType.create');//->withErrors();
$this->assertSessionHasErrors('name');
}
}
My EloquentMealTypeRepository:
Nothing really interesting.
class EloquentMealTypeRepository implements MealTypeRepositoryInterface
{
public function all()
{
return MealType::all();
}
public function find($id)
{
return MealType::find($id);
}
public function create($input)
{
return MealType::create($input);
}
public function getValidator($input)
{
return MealType::getValidator($input);
}
}
My eloquent implementation:
Nothing really interresting,too.
class MealType extends Model
{
private $validator;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'meal_types';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [];
public function meals()
{
return $this->hasMany('Meal');
}
public static function getValidator($fields)
{
return Validator::make($fields, ['name' => 'required|min:3'] );
}
}
My MealTypeRepositoryInterface:
interface MealTypeRepositoryInterface
{
public function all();
public function find($id);
public function create($input);
public function getValidator($input);
}
And finally, My controller:
class MealTypeController extends Controller {
protected $mealType;
public function __construct(MealType $mealType)
{
$this->mealType = $mealType;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$mealTypes = $this->mealType->all();
return View::make('mealTypes.index')->with('mealTypes' ,$mealTypes);
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$mealType = new MealTypeEloquent;
$action = 'MealTypeController#store';
$method = 'POST';
return View::make('mealTypes.create_edit', compact('mealType' , 'action' , 'method') );
}
/**
* Validator does not work properly in tests.
* Store a newly created resource in storage.
*
* #return Response
*/
public function store(Request $request)
{
$input = ['name' => $request->input('name')];
$mealType = new $this->mealType;
$v = $mealType->getValidator($input);
if( $v->passes() )
{
$this->mealType->create($input);
return Redirect::to('mealType');
}
else
{
$this->errors = $v;
return Redirect::to('mealType/create')->withErrors($v);
}
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
return View::make('mealTypes.show' , ['mealType' => $this->mealType->find($id)]);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
$mealType = $this->mealType->find($id);
$action = 'MealTypeController#update';
$method = 'PATCH';
return View::make('mealTypes.create_edit')->with(compact('mealType' , 'action' , 'method'));
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
$mealType = $this->mealType->find($id);
$mealType->name = \Input::get('name');
$mealType->save();
return redirect('mealType');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
$this->mealType->find($id)->delete();
return redirect('mealType');
}
}
That should be everything. It's worth to say that the application works, just tests are screwed up.
Does anybody know, why is that happening? I cant see a difference between methods of TestCase - testIndex and testStoreFails, why method "all" is found and "getValidator" is not.
I will be thankful for any tips of advices.
Perhaps an aside, but directly relevant to anyone finding this question by its title:
If:
You are getting the error BadMethodCallException: Method Mockery_0_MyClass::myMethod() does not exist on this mock object, and
none of your mocks are picking up any of your subject's methods, and
your classes are being autoloaded, (e.g. using composer)
then before making your mock object, you need to force the loading of that subject, by using this line of code:
spl_autoload_call('MyNamespace\MyClass');
Then you can mock it:
$mock = \Mockery::mock('MyNamespace\MyClass');
In my PHPUnit tests, I often put that first line into the setUpBeforeClass() static function, so it only gets called once and is isolated from tests being added/deleted. So the Test class looks like this:
class MyClassTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
spl_autoload_call('Jodes\MyClass');
}
public function testIt(){
$mock = \Mockery::mock('Jodes\MyClass');
}
}
I have forgotten about this three times now, each time spending an hour or two wondering what on earth the problem was!
I have found a source of this bug in controller.
calling wrong
$v = $mealType->getValidator($input);
instead of right
$v = $this->mealType->getValidator($input);
Well, I think the title explains most of it. Lets get right into it!
Blank Model:
class Blank extends Eloquent
{
protected $table = 'blanks';
protected $softDelete = true;
protected $hidden = array();
/**
* Get associated jobs.
*
* #return mixed
*/
public function jobs()
{
return $this->belongsToMany('Job')->withPivot('status', 'inventory', 'sizes', 'mill', 'po', 'location', 'ordered_at', 'expected_at', 'note')->withTimestamps();
}
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($this->pivot->sizes);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->pivot->attributes['sizes'] = json_encode($this->pivot->sizes);
}
}
Job Model:
class Job extends Eloquent
{
protected $table = 'jobs';
protected $softDelete = true;
protected $hidden = array();
/**
* Get associated blank.
*
* #return mixed
*/
public function blanks()
{
return $this->belongsToMany('Blank')->withPivot('status', 'inventory', 'sizes', 'mill', 'po', 'location', 'ordered_at', 'expected_at', 'note')->withTimestamps();
}
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($this->pivot->sizes);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->pivot->attributes['sizes'] = json_encode($this->pivot->sizes);
}
}
Attaching Code:
$job->blanks()->attach($blank->id,[
'status' => Input::get('status'),
'inventory' => Input::get('inventory'),
//'sizes' => $sizes,
'mill' => Input::get('mill'),
'po' => Input::get('po'),
'location' => Input::get('location'),
'ordered_at' => Carbon::parse(Input::get('ordered_at'))->format('Y-m-d H:i:s'),
'expected_at' => Carbon::parse(Input::get('expected_at'))->format('Y-m-d H:i:s'),
'note' => Input::get('note'),
]);
The mutator is not being called at all.. Any ideas?
Seems like that not possible to do this through ::attach() method.
But maybe you would like to use 'Defining A Custom Pivot Model'
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
return new YourCustomPivot($parent, $attributes, $table, $exists);
}
So, you can define your own pivot class with mutators:
class BlankJobPivot extends Eloquent
{
// ...
/**
* Blanks sizes accessor
*
* #return object
*/
public function getSizesAttribute($value)
{
return json_decode($value);
}
/**
* Blanks sizes mutator
*
* #return void
*/
public function setSizesAttribute($value)
{
$this->attributes['sizes'] = json_encode($value);
return $value; // return for multiple assignment statement: $arr = $pivot->sizes = array(12, 23, 34);
}
}
And than you can use getters:
$blank->jobs[$i]->pivot->sizes; // - ::getSizesAttribute() will called ( I hope :) )
And maybe you will find a way to save / attach through the setSizesAttribute mutator.
Good luck.