I have the following models.
Ticket
class Ticket extends Model
{
protected $fillable = ['title', 'content', 'slug', 'status', 'user_id'];
protected $guarded = ['id'];
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
public function comments()
{
return $this->hasMany('App\Comment', 'post_id', 'id');
}
public function commenters()
{
return $this->hasManyThrough('App\User', 'App\Comment');
}
}
Comment
class Comment extends Model
{
protected $guarded = ['id'];
public function user()
{
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function ticket()
{
return $this->belongsTo('App\Ticket', 'post_id', 'id');
}
public function post()
{
return $this->morphTo();
}
}
User
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use Authenticatable, CanResetPassword;
protected $guarded = ['id'];
protected $hidden = [
'password', 'remember_token',
];
}
A ticket has many comments
A comment has one user
I'm trying to extract a name-string list of users who commented on a ticket, but with no success.
In my controller, I'm using the following code to extract the list of commenters.
Ticket::where('id', $comment->post_id)->commenters
However, I'm getting the error:
Property [commenters] does not exist on the Eloquent builder instance.
You're missing a closure. This query is unfinished:
Ticket::where('id', $comment->post_id)
And an unfinished query is an instance of the Builder class, not a Ticket instance, or Collection of Ticket instances as you're expecting.
If you're expecting a single Ticket instance, then you'd use ->first():
$ticket = Ticket::where('id', $comment->post_id)->with(['commenters'])->first();
$commenters = $ticket->commenters;
If you're expecting multiple Ticket instances, then you'd use ->get():
$tickets = Ticket::where('id', $comment->post_id)->with(['commenters'])->get();
foreach($tickets AS $ticket){
$commenters = $ticket->commenters;
}
Note: ->with(['commenters']) is used to speed up the loading of ->commenters; if you omit it, then a new query is run when you try to access $ticket->commenters.
Related
i have a problem that make my head blow about eloquent went to the wrong table here my code for my activity model
class Activity extends Model{
use HasFactory;
protected $table = 'activities';
protected $guarded = ['id'];
public function getRouteKeyName()
{
return 'slug';
}
and the problem is when i store to the database, eloquent went to the wrong table
here is my store method
public function store(StoreActivityRequest $request)
{
$validatedData = $request->validate([
'name' => 'required',
'slug' => 'required|unique:activies'
]);
Activity::create($validatedData);
return redirect('/activities')->with('success', 'Tindakan Berhasil Ditambahkan');
}
this is my customrequest (actually my laravel make it by default)
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreActivityRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
//
];
}
}
here is the message
Illuminate\Database\QueryException
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'klinik_app.activies' doesn't exist (SQL: select count(*) as aggregate from `activies` where `slug` = konsultasi)
its go to activies table... if i change the tables on migrate file to activies, then the other method gone wrong because it's can't found activities. and this problem just happen to my store method, another method just do the right thing... is there any body can help me?
Update: Added from comments:
public function store(StoreActivityRequest $request) {
$validatedData = $request->validate([
'name' => 'required',
'slug' => 'required|unique:activies'
]);
Activity::create($validatedData);
return redirect('/activities')->with('success', 'Tindakan Berhasil Ditambahkan');
}
I have Employee table whose structure is as follows:
EmpId
FirstName
LastName
Username
Password
Now in application component I have included my custom class as follows:
'user' => [
'identityClass' => 'app\models\Employee',
'enableSession' => true,
],
I have implemented foll methods in Employee model as follows:
public static function findIdentityByAccessToken($token, $type = null)
{
throw new NotSupportedException();
}
public function getId()
{
return $this->EmpId;
}
public function getAuthKey()
{
throw new NotSupportedException();
}
public function validateAuthKey($authKey)
{
throw new NotSupportedException();
}
public static function findByUsername($username)
{
return self::findOne(['Username'=>$username]);
}
public function validatePassword($password)
{
return $this->Password === $password;
}
And in LoginForm model, I have following. Insted of User, I have included
custom class Employee.
public function getUser()
{
if ($this->_user === false)
{
$this->_user = Employee::findByUsername($this->username);
}
return $this->_user;
}
Now when I try to login and provide username and password, it gives the foll error:
Unknown Property – yii\base\UnknownPropertyException
Getting unknown property: app\models\Employee::username
Notice the Case in the column names in your - this should be the same as attributes in your model.
ie: replace -
$this->usename to $this->Username;
Im am new in Zend Framework.
I have this structure of codes .
DBTable
class Application_Model_DbTable_Employee extends Zend_Db_Table_Abstract
{
protected $_name = 'tab_employee';
}
Model
public function selectAllEmployees(){
$tblEmployee = new Application_Model_DbTable_Employee();
$tblEmployee->select('*');
}
But i can can't get all the data of all the employee .
public function selectAllEmployees(){
$tblEmployee = new Application_Model_DbTable_Employee();
return $tblEmployee->fetchAll($tblEmployee->select());
}
Try this code in model:
public function selectAllEmployees(){
$tblEmployee = new Application_Model_DbTable_Employee();
$rowset = $tblEmployee->fetchAll();
return $rowset;
}
For further information read this http://framework.zend.com/manual/1.12/en/zend.db.table.rowset.html#zend.db.table.rowset.to-array
Model function
public function selectAllEmployees()
{
$selectSql = $this->select();
$selectSql->from($this->_name, array('*'))
->order(id DESC');
return $this->fetchAll($selectSql);
}
in the controller
$employeeModel = new Application_Model_Employee();
$employees = $employeeModel->selectAllEmployees();
Maks3w is correct as well as terse.
Here is a little more detail.
There are a number of ways to use your Application_Model_DbTable_Employee to access and query your tab_employee table of your database.
The easiest way is to query directly from the dbTable model itself:
class Application_Model_DbTable_Employee extends Zend_Db_Table_Abstract
{
protected $_name = 'tab_employee';
public function selectAllEmployees()
{
//$this refers to the current dbTable object
$select = $this->select();
//when querying from the dbTable the from() parameter is assumed to be $this->_name, array('*')
//there several other sql commands available to the select(), where(), orWhere(), join()
$select->order('id DESC');
$result = $this->fetchAll($select);
return $result;
}
}
Controller code:
public function indexAction(){
model = new Application_Model_DbTable_Employee();
$employees = $model->selectAllEmployees();
$this->view->employees = $employees
}
Often a mapper model is used to access the database and provide the data to an entity model. This is also very common a relatively simple to accomplish. The key item to remember when designing the mapper is to include code to access the dbTable model as the database adapter, often called the gateway, here is some example code:
<?php
//This is one way to build a mapper
abstract class My_Model_Mapper_Abstract
{
/**
* Instance of Zend_Db_Table_Abstract
*/
protected $tableGateway = null;
/**
* Will accept a DbTable model passed or will instantiate
* a Zend_Db_Table_Abstract object from table name.
*/
public function __construct(Zend_Db_Table_Abstract $tableGateway = null)
{
if (is_null($tableGateway)) {
$this->tableGateway = new Zend_Db_Table($this->_tableName);
} else {
$this->tableGateway = $tableGateway;
}
}
/**
* Get default database table adapter
*/
protected function getGateway()
{
return $this->tableGateway;
}
/**
* findAll() is a proxy for the fetchAll() method and returns
* an array of entity objects.
*
* #param $where, primary key id
* #param string $order in the format of 'column ASC'
* #return array of entity objects
*/
public function findAll($where = null, $order = null)
{
$select = $this->getGateway()->select();
if (!is_null($where)) {
$select->where('id = ?', $where);
}
if (!is_null($order)) {
$select->order($order);
}
$rowset = $this->getGateway()->fetchAll($select);
$entities = array();
foreach ($rowset as $row) {
$entity = $this->createEntity($row);
$this->setMap($row->id, $entity);
$entities[] = $entity;
}
return $entities;
}
/**
* Abstract method to be implemented by concrete mappers.
*/
abstract protected function createEntity($row);
}
The concrete model might look like:
<?php
class Application_Model_Mapper_Employee extends My_Model_Mapper_Abstract
{
protected $tableName = 'tab_employee';
//I hard code the $tableGateway though this is probably not the best way.
//$tableGateway should probably be injected, but I'm lazy.
public function __construct(Zend_Db_Table_Abstract $tableGateway = null)
{
if (is_null($tableGateway)) {
$tableGateway = new Application_Model_DbTable_User();
} else {
$tableGateway = $tableGateway;
}
parent::__construct($tableGateway);
}
//create the Entity model
protected function createEntity($row)
{
$data = array(
'id' => $row->id,
'name' => $row->name,
'password' => $row->password,
);
$employee = new Application_Model_Employee($data);
return $employee;
}
}
to use this in a controller might look like:
public function indexAction(){
model = new Application_Model_Mapper_Employee();
$employees = $model->findAll();
}
and the most direct way to query your database is least recommended way, directly from the controller:
public function indexAction(){
model = new Application_Model_DbTable_Employee();
$employees = $model->fetchAll();
$this->view->employees = $employees
}
I hope this provides you some help and not to much confusion.
I have class that representing model of user with foreign key with is id of picture .
class Model_User extends Model_AbstractEntity
{
protected $u_id;
protected $u_email;
protected $u_firstname;
protected $u_lastname;
protected $u_password;
protected $u_salt;
protected $u_created_at;
protected $u_updated_at;
protected $u_fb;
protected $u_status;
protected $u_r_id;
protected $u_p_id;
}
Class with is responsible for picture model look like this:
class Model_Picture extends Model_AbstractEntity
{
protected $p_id;
protected $p_created_at;
protected $p_updated_at;
protected $p_caption;
protected $p_name;
protected $p_basePath;
protected $p_available;
protected $p_u_id;
}
This is only model part with is getting data from database.
Foreing key is u_p_id and key in picture is p_id
My problem is that when doing select() by Zend db table it returning me data with foreign key but how can I know which part of return data is picture part to set the proper picture model.... how to do it in proper way no to do 2 queries one for user and second for picture to create 2 associative objects.
I'm talking now about relation ont to one but maybe will be one to many..
Typically your entity models will not exist in void they will exist in concert with some type of Data Mapper Model. The Mapper will typically be charged with gathering the data from whatever source is handy and then constructing the entity model.
For example I have a music collection that has an album entity:
<?php
class Music_Model_Album extends Model_Entity_Abstract implements Interface_Album
{
//id is supplied by Entity_Abstract
protected $name;
protected $art;
protected $year;
protected $artist; //alias of artist_id in Database Table, foreign key
protected $artistMapper = null;
/**
* Constructor, copied from Entity_Abstract
*/
//constructor is called in mapper to instantiate this model
public function __construct(array $options = null)
{
if (is_array($options)) {
$this->setOptions($options);
}
}
/**
* Truncated for brevity.
* Doc blocks and normal getters and setters removed
*/
public function getArtist() {
//if $this->artist is set return
if (!is_null($this->artist) && $this->artist instanceof Music_Model_Artist) {
return $this->artist;
} else {
//set artist mapper if needed
if (!$this->artistMapper) {
$this->artistMapper = new Music_Model_Mapper_Artist();
}
//query the mapper for the artist table and get the artist entity model
return $this->artistMapper->findById($this->getReferenceId('artist'));
}
}
//set the artist id in the identity map
public function setArtist($artist) {
//artist id is sent to identity map. Can be called later if needed - lazy load
$this->setReferenceId('artist', $artist);
return $this;
}
//each album will have multiple tracks, this method allows retrieval as required.
public function getTracks() {
//query mapper for music track table to get tracks from this album
$mapper = new Music_Model_Mapper_Track();
$tracks = $mapper->findByColumn('album_id', $this->id, 'track ASC');
return $tracks;
}
}
In the mapper I would build the entity model like:
//excerpt from Model_Mapper_Album
//createEntity() is declared abstract in Model_Mapper_Abstract
public function createEntity($row)
{
$data = array(
'id' => $row->id,
'name' => $row->name,
'art' => $row->art,
'year' => $row->year,
'artist' => $row->artist_id,//
);
return new Music_Model_Album($data);
}
to use this method in a mapper method, might look like:
//this is actually from Model_Mapper_Abstract, b ut give the correct idea and will work in any of my mappers.
//this returns one and only one entity
public function findById($id)
{
//if entity id exists in the identity map
if ($this->getMap($id)) {
return $this->getMap($id);
}
//create select object
$select = $this->getGateway()->select();
$select->where('id = ?', $id);
//fetch the data
$row = $this->getGateway()->fetchRow($select);
//create the entity object
$entity = $this->createEntity($row);
//put it in the map, just in case we need it again
$this->setMap($row->id, $entity);
// return the entity
return $entity;
}
I have seen Entities and Mappers built in many different ways, find the method that you like and have fun.
A lot of code has been left out of this demonstration as it doesn't really apply to the question. If you need to see the complete code see it at GitHub.
So I have my controller action similar to this
$task1 = new Task();
$form1 = $this->createForm(new MyForm(), $task1);
$task2 = new Task();
$form2 = $this->createForm(new MyForm(), $task2);
And let's say my MyForm has two fields
//...
$builder->add('name', 'text');
$builder->add('note', 'text');
//...
It seems like since the two forms are of the same type MyForm, when rendered in the views, their fields have the same name and IDs (the 'name' fields of two forms share the same name and id; the same goes for the 'note' fields), because of which Symfony may not bind the forms' data correctly. Does anyone know any solution to this?
// your form type
class myType extends AbstractType
{
private $name = 'default_name';
...
//builder and so on
...
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
}
// or alternativ you can set it via constructor (warning this is only a guess)
public function __constructor($formname)
{
$this->name = $formname;
parent::__construct();
}
}
// you controller
$entity = new Entity();
$request = $this->getRequest();
$formType = new myType();
$formType->setName('foobar');
// or new myType('foobar'); if you set it in the constructor
$form = $this->createForm($formtype, $entity);
now you should be able to set a different id for each instance of the form you crate.. this should result in <input type="text" id="foobar_field_0" name="foobar[field]" required="required> and so on.
I would use a static to create the name
// your form type
class myType extends AbstractType
{
private static $count = 0;
private $suffix;
public function __construct() {
$this->suffix = self::$count++;
}
...
public function getName() {
return 'your_form_'.$this->suffix;
}
}
Then you can create as many as you want without having to set the name everytime.
EDIT: Do not do that! See this instead: http://stackoverflow.com/a/36557060/6268862
In Symfony 3.0:
class MyCustomFormType extends AbstractType
{
private $formCount;
public function __construct()
{
$this->formCount = 0;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
++$this->formCount;
// Build your form...
}
public function getBlockPrefix()
{
return parent::getBlockPrefix().'_'.$this->formCount;
}
}
Now the first instance of the form on the page will have "my_custom_form_0" as its name (same for fields' names and IDs), the second one "my_custom_form_1", ...
create a single dynamic name :
const NAME = "your_name";
public function getName()
{
return self::NAME . '_' . uniqid();
}
your name is always single