I have a code something like following
class Application_Model_Company extends Zend_Db_Table_Abstract {
protected $_name = 'companies';
private $id;
private $name;
private $shortName;
private $description;
public static function getAllCompanies() {
$companyObj = new self();
$select = $companyObj->select()->order(array('name'));
$rows = $companyObj->fetchAll($select);
if($rows) {
$companies = array();
foreach($rows as $row) {
$company = new self();
$company->id = $row->id;
$company->name = $row->name;
$company->shortName = $row->short_name;
$company->description = $row->description;
$companies[] = $comapny;
}
// return Company Objects
return $companies;
}else
throw new Exception('Oops..');
}
}
I need to return Company Objects from getAllCompanies() function, But it returns Zend_Db_Table_Row Object. How do I correct this?
Your Model class shouldnt extend the table class. The table class is separate. Your Model should extend the row class if extending anything from Zend_Db at all. Also you shouldnt put retrieval methods on your Model classes directly, they would go on the table classes.
This is because in the paradigm youre trying to use here, a Model represents a single Row of data, the Table class represents the table as a repository of data, and the Rowset class represents a collection of Rows (or Models).
To properly implement what you are describing in your question you would do something like the following:
class Application_Model_DbTable_Company extends Zend_Db_Table_Abstract
{
// table name
protected $_name = 'company';
protected _$rowClass = 'Application_Model_Company';
// your custom retrieval methods
}
class Application_Model_Company extends Zend_Db_Table_Row
{
protected $_tableClass = 'Application_Model_DbTable_Company';
// custom accessors and mutators
}
However, using some kind of implementation of the Data Mapper pattern is whats actually recommended. Check out the Quickstart for a thorough tutorial on a simplified implementation.
Related
I would like to extend the extension cart with a new field to put in the IBAN in the checkout.
So I created a new extension and added a database field with the following code in ext_tables.sql
#
# Table structure for table 'tx_cart_domain_model_order_item'
#
CREATE TABLE tx_cart_domain_model_order_item (
iban varchar(255) DEFAULT '' NOT NULL
);
Now I need to extend the class Item in
ext/cart/Classes/Domain/Model/Order/item.php
I tried to create a file in my extension
ext/cartextend/Classes/Domain/Model/Order/item.php
and tried to extend the class with:
namespace Extcode\Cart\Domain\Model\Order;
use Extcode\Cart\Property\Exception\ResetPropertyException;
class Item extends \Extcode\Cart\Domain\Model\Order
{
/**
* Iban
*
* #var string
*/
protected $iban;
/**
* #return string
*/
public function getIban()
{
return $this->iban;
}
/**
* #param string $iban
*/
public function setIban($iban)
{
$this->iban = $iban;
}
}
I also added an input field that is implemented correctly.
But the IBAN is not saved at all - i guess the extending of the class is wrong.
I really appreciate any hint.
Many thanks! Urs
Maybe you have to extend item.php like this (the rest looks fine):
namespace Extcode\YourExtension\Domain\Model\Order;
class Item extends \Extcode\Cart\Domain\Model\Order\Item
and do not forget to make it known to extbase for you to use iban in the front-end trough typoscript: (I have it to extend cart_products, you'll have to adept it)
config.tx_extbase {
persistence {
classes {
Extcode\CartExtendedProduct\Domain\Model\Product\Product {
mapping {
tableName = tx_cartproducts_domain_model_product_product
recordType =
}
}
}
}
objects {
Extcode\CartProducts\Domain\Model\Product\Product.className = Extcode\CartExtendedProduct\Domain\Model\Product\Product
}
}
I have three models.
Study
Site
Unit
Study Has and belongs to many Sites and each site that belongs to Study again has and belongs to many Unit. Please see the following drawing.
http://tinypic.com/r/ojhx0g/8
How I achieve this using Laravel 5 Eloquent Relationships.
It sounds like you have many-to-many relationships between Study->Site and Site->Unit. You can read the Laravel documentation about many-to-many relationships here.
Models
Here are the relevant functions you'll need for Eloquent to recognize the relationships.
class Study extends Model {
// If you named your table differently (like 'studies'), specify that here
protected $table = 'studys';
// This assumes a pivot table named 'site_study', if you named yours
// differently you can pass in into the belongsToMany() function as the
// second parameter.
public function sites() {
return $this->belongsToMany('App\Site');
}
}
class Site extends Model {
protected $table = 'sites';
public function studies() {
return $this->belongsToMany('App\Study');
}
public function units() {
return $this->belongsToMany('App\Unit');
}
}
class Unit extends Model {
protected $table = 'units';
public function sites() {
return $this->belongsToMany('App\Site');
}
}
Then, to access the Sites belonging to a Study you would do this:
$sites = Study::find(1)->sites;
Pivot Table Migrations
Laravel expects pivot tables to be named like 'alpha_beta' where alpha and beta are the singular model names in alphabetical order. So your migrations for the pivot tables would look like this:
class CreateSiteStudyTable extends Migration {
public function up() {
Schema::create('site_study', function(Blueprint $table)) {
$table->integer('site_id')->unsigned();
$table->foreign('site_id')->references('id')->on('sites');
$table->integer('study_id')->unsigned();
$table->foreign('study_id')->references('id')->on('studys'); // or whatever you named it
$table->unique(['site_id', 'study_id']);
$table->timestamps();
});
}
public function down() {
Schema::drop('site_study');
}
}
class CreateSiteUnitTable extends Migration {
public function up() {
Schema::create('site_unit', function(Blueprint $table)) {
$table->integer('site_id')->unsigned();
$table->foreign('site_id')->references('id')->on('sites');
$table->integer('unit_id')->unsigned();
$table->foreign('unit_id')->references('id')->on('units');
$table->unique(['site_id', 'unit_id']);
$table->timestamps();
});
}
public function down() {
Schema::drop('site_unit');
}
}
You can read about Foreign Keys in Laravel here.
you have to create 3 models study, site and unit as per you diagram study has many sites and sites has many units, in you diagram study don't have direct relation with units your eloquent models will be like this.
class Study extends Model {
public function sites(){
return $this->hasMany('App\Site');
}
}
class Site extends Model {
public function units(){
return $this->hasMany('App\Unit');
}
public function study(){
return $this->belongsTo('App\Study');
}
}
class Unit extends Model {
public function sites(){
return $this->belongsTo('App\Site');
}
}
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.
I have a project in which I use more than one adapter.
So In ma models i created an abstract model
abstract My_Config1_Model extends Zend_Db_Table_Abstract
{
public function init()
{
$db = Zend_Registry::get('dbcon')->getDb(Kiga_Data_Database::MASTER);
$this->setDefaultAdapter($db);
}
}
and then I inherit this abstaract class like:
class MyModel extends My_Config1_Model
{
protected $_name = 'mytable';
protected $_primary = 'id';
protected $_rowClass = 'MyRow';
}
class MyRow extends Zend_Db_Table_Row_Abstract
{
}
and the in my controller I try:
$table = new MyModel();
when I fetch alll it works:
$results = $table->fetchAll(); // works fine
but when I try to filter it it does not work:
results = $table->fetchRow("id = 1"); // Does not work. I get the error Error: No adapter for type MyRow.
Anybody any Idea?
Thanks.
I forgot I use also paginator
$paginator = Zend_Paginator::factory($results);
That's not the place you should set the Db adapter for this table.
The init() method is called after the table class has parsed its options and set up the adapter for the table. So all you've accomplished is to set the default Db adapter for subsequent table construction, but it has no effect on the current table if you do this in the init() method.
Consider this simplified example:
class MyTable
{
static $defaultDb;
protected $db;
static function setDefaultDb($db) { self::$defaultDb = $db; }
public function __construct() {
$this->db = self::$defaultDb;
$this->init();
}
public function init() {
// Unfortunately, PHP allows you to run static methods
// as if they are non-static methods, which is confusing.
$this->setDefaultDb($globalDb);
}
}
This example is a simplified model of the way Zend_Db_Table constructs. Note that the init() method sets the class default Db, but this is run after the constructor has already set the instance Db to be the class default Db. So setting the class default Db has no effect.
There are several ways you can set the Db adapter for a table:
For all tables, using the static method setDefaultAdapter(). The intended way to use setDefaultAdapter() is as follows:
Zend_Db_Table_Abstract::setDefaultAdapter($db);
// now all tables will use $db by default
$table = new MyModel();
As a constructor argument:
$table = new MyModel(array('db'=>$db));
You might also be able to use the setOptions() method after the table class has been instantiated.
$table = new MyModel(); // uses default Db
$table->setOptions(array('db'=>$otherDb));
But be aware that the table reads its metadata from the default Db during construction, so if you change the adapter subsequently, the table should be defined identically in both databases.