i have two tables users and userslog where i have users contains id, username,email,gender and userslog contains id,firstname,lastname,designation and u_id which is foreign key of users table.
my register controller
class RegisterController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
$form = new Application_Form_register();
$this->view->form = $form;
if($this->getRequest()->isPost())
{
$data = $this->getRequest()->getPost();
}
}
}
my register model is
class Application_Model_DBtable_register extends Zend_Db_Table
{
protected $_name = 'users';
// i have to define two tables here!! how?
}
my register zend form
class Application_Form_register extends Zend_Form
{
public function init()
{
$this->setName('register');
$this->setMethod('post');
$firstname = $this->createElement('text', 'firstname');
$firstname->setLabel('FirstName: ')
->setRequired(true)
->setFilters(array(
'stringTrim','StringToLower'));
$lastname = $this->createElement('text', 'lastname');
$lastname->setLabel('LastName: ')
->setRequired(true)
->setFilters(array(
'stringTrim','StringToLower'));
$email = $this->createElement('text', 'email');
$email->setLabel('Email: ')
->setRequired(true);
$username = $this->createElement('text', 'username');
$username->setLabel('UserName: ')
->setRequired(true)
->setFilters(array(
'stringTrim','StringToLower'));
$password = $this->createElement('password', 'password');
$password->setLabel('Password: ')
->setRequired(true);
$password2 = $this->createElement('password', 'password2');
$password2->setLabel('Confirm Password: ')
->setRequired(true);
$submit = $this->createElement('submit', 'register');
$submit->setLabel('Register')
->setIgnore(true);
$this->addElements(array(
$firstname,
$lastname,
$email,
$username,
$password,
$password2,
$submit));
}
}
how can i do it? can we use Zend_Auth for authentication? if yes then how.please give me example. I saw $_dependantTable and $_referenceMaps but i can't undestand it . I am confused how to do it because i am not able to define table name more than once in a class. i have to insert the values at same time in two different tables.
So as to insert values in users and userslog tables, you can try it:
In your RegisterController:
$db = new Application_Model_DBtable_register();
$db->instertValuesInUsers(array('column_name' => $data['value'], 'column_name' => $data['value'], ...........));
$db->insertValuesInUserslog(array('column_name' => $data['value'], 'column_name' => $data['value'], ...........));
In you Application_Model_DBtable_register:
public function instertValuesInUsers(array $data) {
$this->insert($data);
}
public function insertValuesInUserslog(array $data) {
$db = new Zend_Db_Table(array('name' => 'userslog'));
$db->insert($data);
}
ok this is incorrect:
class Application_Model_DBtable_register extends Zend_Db_Table
{
protected $_name = 'users';
// i have to define two tables here!! how?
}
The intent of classes that have DbTable in their names is that they they are the adapter/gateway to a single database table.
So your issue would breakdown into at least 2 classes/files:
class Application_Model_DBtable_Users extends Zend_Db_Table
{
protected $_name = 'users';
}
class Application_Model_DBtable_Userslog extends Zend_Db_Table
{
protected $_name = 'userslog';
}
I would at this level put a method in either class that does the actions required to register a user. Later you may decide to use mappers and domain objects.
class Application_Model_DBtable_Users extends Zend_Db_Table
{
protected $_name = 'users';
/*
* psuedocode not meant for production
*/
public function register($array $data) {
//sort out the data
$user = array();//put the elements from the $data array that you want to go into the users table
$userLog = array(); //same thing for the userslog table
//get userslog adapter
$userlogTable = new Application_Model_DbTable_Userslog();
//do the first insert
$result = $this->insert($user);
//insert returns the primary key of the row created,
$u_id = array('u_id' => $result);
$userLog = array_merge($u_id, $userLog); //merge u_id with existing data
//perform second insert
$result2 = $userlogTable->insert($userLog);
//handle any errors
}
}
This should provide a basic example to demonstrate the steps you might take to implement you design. The point behind the DbTable models is to abstract the connection to a given table, each table has it's own DbTable model. The DbTable model provides an adapter to each table and access to the api provided by Zend_Db_Table_Abstract.
The Steps shown above could just as easily be taken in a third model or in the controller itself.
Note: There may be away to do this with one sql statement but I'm not the person who knows that answer.
Related
I have this model:
class Application_Model_Categories extends Zend_Db_Table_Abstract
{
protected $_name = 'categories';
protected $_referenceMap = array(
'Stores' => array (
'columns' => 'store_id',
'refTableClass' => 'Application_Model_Races',
'refColumns' => 'id')
);
}
Then in my controller:
$race = new Application_Model_Races();
$find = $this->race->find(1);
$current = $find->current();
$categories = $current->findDependentRowset('Application_Model_Categories');
this is returning all the categories. i need to apply a filter to return only the categories with parentId = 0
I´m new to ZF1 so if you also see that im getting the data incorrectly in the controller please let me know. thank you
Simply,
$race = new Application_Model_Races();
$find = $this->race->find(1);
$current = $find->current();
$select = $race->getAdapter()->select()->where('parentId = 0');
$categories = $current->findDependentRowset(
'Application_Model_Categories',
null,
$select
);
By providing a Zend_Db_Select object as third argument to findDependentRowset table row method call, you can add as much conditions as you want (even adding limit, setting order, ...).
Edit
Well, you should create a custom Row Class, name it Application_Model_Race for example, or Application_Model_RaceRow.
class Application_Model_RaceRow extends Zens_Db_Table_Row_Abstract
{
public function getParentCategories()
{
$select = $this->getTable()->select()->where('parentId = 0');
return $this->findDependentRowset(
'Application_Model_Categories',
null,
$select
);
}
}
Add a _rowClass to your Application_Model_Races class.
class Application_Model_Races extends Zend_Db_Table_Abstract
{
protected $_rowClass = 'Application_Model_RaceRow';
/** Your old code **/
}
Hope it helps
I have over 100 tables. I need to access each of these tables depending on a username that is provide on a form. The username is the table name. I do not not want to create 100 of classes for each one representing a table. Is there a way i can do this?
I use this code similar to this in my base mapper class:
protected $_tableGateway = NULL;
protected $_tableName = NULL;
public function __construct(Zend_Db_Table_Abstract $tableGateway = NULL, $tableName = NULL) {
//set the tablename in a concrete mapper, set it here in constructor or create mutator to setTableName.
if (!is_null($tableName)) {
$this->_tableName = $tableName;
}
if (is_null($tableGateway)) {
$this->_tableGateway = new Zend_Db_Table($this->_tableName);
} else {
$this->_tableGateway = $tableGateway;
}
}
Something like this should allow you to pass in an instance of Zend_Db_Table_Abstract (DbTable model) or a string that is the name of the table.
//controller code
$username = $form->getValue('username');
$mapper = My_Mapper(NULL, $username);
$result = $mapper->fetchAll();
I don't think this is really finished, but should help show the way.
If you are not using mappers and just want to use DbTable Models you might try (this could be passed to a mapper that accepts Zend_Db_Table_Abstract):
class Application_Model_DbTable_Users extends Zend_Db_Table_Abstract
{
function __construct(array $config) {
parent::__construct($config);
}
}
and to use this in your controller/action:
/**
* Supported params for $config are:
* - db = user-supplied instance of database connector,
* or key name of registry instance.
* - name = table name.
* - primary = string or array of primary key(s).
* - rowClass = row class name.
* - rowsetClass = rowset class name.
* - referenceMap = array structure to declare relationship
* to parent tables.
* - dependentTables = array of child tables.
* - metadataCache = cache for information from adapter describeTable().
*/
$username = $form->getValue('username');
$config = array('name'=> $username, 'primary' => 'id');
$model = new Application_Model_DbTable_Users($config);//This should setup your table
$result = $model->fetchAll(); //perform queries or execute methods defined in DbTable model
or you could just use Zend_Db_Table naked in your controller/action:
$username = $form->getValue('username');
$db = new Zend_Db_Table($username);
$result = $db->fetchAll();
Good Luck...
Thanks in advance...see below the code.. i have 2 models, category and product
my product model
class Admin_Model_Product extends Zend_Db_Table_Abstract {
protected $_name = 'products';
protected $_referenceMap = array(
'category' => array(
'columns' => array('category_id'),
'refTableClass' => 'Admin_Model_Category',
'refColumns' => array('id'),
'onDelete' => self::CASCADE,
'onUpdate' => self::RESTRICT
)
);
}
my category model is:
class Admin_Model_Category extends Zend_Db_Table_Abstract {
protected $_name = 'categories';
protected $_dependentTables = array('Admin_Model_Product');
}
in my products controller i have
class Admin_ProductsController extends Zend_Controller_Action {
public function init() {
}
public function indexAction() {
echo '<pre>';
$model = new Admin_Model_Product();
}
}
What i need to do is get all the products using fetchAll() method and need to get parentrow of each product and display it in my view... i can pull all the products but i dont know how to find each products parent category and bind them, is there any example source code? or any suggestion ? i need an array containg all products and parent category name ..please be quick.thanks
Best way to accomplish this would be iterating over products result and creating array containg all categories_ids, then query the Category Model with where('category_id IN (?)', $array_of_categories_ids) and then creating an array from categories rowset with id_category => row_pairs. Then You can do this in just two queries :)
$categories_ids = array();
foreach ($products as $product)
{
$categories_ids[ $product->category_id ] = $product->category_id; // set key to category id to avoid duplicated category' ids
}
$categories = $categoryModel->fetchAll($categoryModel->select()->where('id_category in (?)', $categories_ids)); // here u have to add check on array 'coz if empty it will thoro Query exception
// now just iterate over categories
$categories = array();
foreach ($categories as $category)
{
$categories[ $category->id_category ] = $category;
}
// now when iterating over products u can just do $categories[ $product->category_id ] to get proper category for profuct
Anyway sorry for possible typos, wrote it on the fly ;)
try the following :
retrieve categories and their products :
$model_category = new Admin_Model_Category();
$categorySet = $model_category->fetchAll();
$categories = $categorySet->toArray();
$i = 0;
$results = array();
foreach($categories as $category)
$categoryRow = $model_category->fetchRow('id =', $category->category_id)
$products = $categoryRow->findDependentRowset('Admin_Model_Product');
$results[$i]['parent'] = $category;
$results[$i]['products'] = $products;
$i++;
}
then pass it to the view:
$view->results = results;
I'm using Doctrine 2 in a Zend Framework application and require functionality similar to Zend_Validate_Db_RecordExists and Zend_Validate_Db_NoRecordExists.
For example, when a user enters a new item, I need to validate that a duplicate entry doesn't already exist. This is easy to accomplish with Zend_Db by adding the Db_NoRecordExists validator on my forms.
I tried implementing the custom-validator solution proposed here, but I can't figure out how they are communicating with Doctrine to retrieve entities (I suspect this approach may no longer work post-Doctrine 1.x).
The FAQ section of the Doctrine manual suggests calling contains() from the client code, but this only covers collections, and if possible I'd like to handle all of my form validation consistently from within my form models.
Can anyone suggest a way to use these Zend validators with Doctrine 2 DBAL configured as the database connection/resource?
It's quite straightforward, really.
I have a few Zend_Validate-type validators that talk to Doctrine ORM, so I have an abstract class that they descend from.
Here's the abstract class:
<?php
namespace TimDev\Validate\Doctrine;
abstract class AbstractValidator extends \Zend_Validate_Abstract{
/**
* #var Doctrine\ORM\EntityManager
*/
private $_em;
public function __construct(\Doctrine\ORM\EntityManager $em){
$this->_em = $em;
}
public function em(){
return $this->_em;
}
}
Here's my NoEntityExists validator:
<?php
namespace TimDev\Validate\Doctrine;
class NoEntityExists extends AbstractValidator{
private $_ec = null;
private $_property = null;
private $_exclude = null;
const ERROR_ENTITY_EXISTS = 1;
protected $_messageTemplates = array(
self::ERROR_ENTITY_EXISTS => 'Another record already contains %value%'
);
public function __construct($opts){
$this->_ec = $opts['class'];
$this->_property = $opts['property'];
$this->_exclude = $opts['exclude'];
parent::__construct($opts['entityManager']);
}
public function getQuery(){
$qb = $this->em()->createQueryBuilder();
$qb->select('o')
->from($this->_ec,'o')
->where('o.' . $this->_property .'=:value');
if ($this->_exclude !== null){
if (is_array($this->_exclude)){
foreach($this->_exclude as $k=>$ex){
$qb->andWhere('o.' . $ex['property'] .' != :value'.$k);
$qb->setParameter('value'.$k,$ex['value'] ? $ex['value'] : '');
}
}
}
$query = $qb->getQuery();
return $query;
}
public function isValid($value){
$valid = true;
$this->_setValue($value);
$query = $this->getQuery();
$query->setParameter("value", $value);
$result = $query->execute();
if (count($result)){
$valid = false;
$this->_error(self::ERROR_ENTITY_EXISTS);
}
return $valid;
}
}
Used in the context of a Zend_Form (which has an em() method like the abstract class above):
/**
* Overrides superclass method to add just-in-time validation for NoEntityExists-type validators that
* rely on knowing the id of the entity in question.
* #param type $data
* #return type
*/
public function isValid($data) {
$unameUnique = new NoEntityExists(
array('entityManager' => $this->em(),
'class' => 'PMS\Entity\User',
'property' => 'username',
'exclude' => array(
array('property' => 'id', 'value' => $this->getValue('id'))
)
)
);
$unameUnique->setMessage('Another user already has username "%value%"', NoEntityExists::ERROR_ENTITY_EXISTS);
$this->getElement('username')->addValidator($unameUnique);
return parent::isValid($data);
}
Check out the RecordExists.php and NoRecordExists.php classes in my project:-
https://github.com/andyfenna/AJF-IT/tree/master/library/AJFIT/Validate
I hope these are some use to you.
Thanks
Andrew
I have a registration form with different input fields one of them being a multi checkbox so that the user can decide what countries he wants to receive information from. This last one is created like this:
$pais = $this->createElement('multiCheckbox', 'pais');
$pais->setLabel('Pais\es: ');
$pais->addMultioption('1', 'Argentina');
$pais->addMultioption('2', 'Espa?a');
$pais->addMultioption('3', 'Brasil');
$pais->addMultioption('4', 'USA');
$pais->addMultioption('5', 'Italia');
$this->addElement($pais);
In my UserController I have the following action to update the table 'users':
public function createAction()
{
$this->view->pageTitle = 'Create User';
require_once APPLICATION_PATH . '/models/Users.php';
$userForm = new Form_User();
if ($this->_request->isPost()) {
if ($userForm->isValid($_POST)) {
$userModel = new Model_User();
$userMode->createUser(
$userForm->getValue('email'),
$userForm->getValue('password'),
$userForm->getValue('url'),
$userForm->getValue('responsable'),
$userForm->getValue('role')
);
return $this->_forward('list');
}
}
$userForm->setAction('/user/create');
$this->view->form = $userForm;
}
which of course, right now is not contemplating the multicheckbox populatedn$pais variable, nor here nor in the model:
class Model_User extends Zend_Db_Table_Abstract
{
protected $_name = 'users';
public function createUser($email, $password, $url, $responsable, $role)
{
// create a new row
$rowUser = $this->createRow();
if($rowUser) {
// update the row values
$rowUser->email = $email;
$rowUser->password = md5($password);
$rowUser->url = $url;
$rowUser->responsable = $responsable;
$rowUser->role = $role;
$rowUser->save();
//return the new user
return $rowUser;
} else {
throw new Zend_Exception("El usuario no se ha podido crear!");
}
}
}
I have also a 'pais' table, which contains the 5 different countries, and I'm working on a separate model for 'users_has_pais' which is the table I created in the workbench for this purpose...but I'm not getting any results with what I'm doing right now. Can someone point me in the right path to get to update 'users_has_pais' at the same time that I update the 'users' table?
Thanks a lot in advance to anyone with good advice on this.
EDIT: this is the db model in case anyone needs it to figure out what I'm saying
EDIT2:
public function createAction()
{
$this->view->pageTitle = 'Create User';
require_once APPLICATION_PATH . '/models/Users.php';
$userForm = new Form_User();
if ($this->_request->isPost()) {
if ($userForm->isValid($_POST)) {
$userModel = new Model_User();
$user = $userModel->createUser(
$userForm->getValue('email'),
$userForm->getValue('password'),
$userForm->getValue('url'),
$userForm->getValue('responsable'),
$userForm->getValue('role')
);
$paises = $this->getRequest()->getParam('pais');
$userId = intval($user['id']);
require_once APPLICATION_PATH . '/models/UserHasPais.php';
$paisesModel = new Model_UsersHasPais();
$paisesModel->updateUserPais($userId, $paises);
return $this->_forward('index');
}
}
and users_has_pais model:
class Model_UsersHasPais extends Zend_Db_Table_Abstract
{
protected $_name = 'users_has_pais';
public function updateUserPais($id, array $paises)
{
$row = ($r = $this->fetchRow(array('users_id = ?' => $id))) ? $r : $this->createRow();
foreach($paises as $pais){
$row->users_id = $id;
$row->pais_id = $pais;
$row->save();
}
}
}
One way would be to create user row first, and use it's ID when creating rows for 'user_has_pais'. A pseudo-code is below:
public function createAction()
{
$this->view->pageTitle = 'Create User';
require_once APPLICATION_PATH . '/models/Users.php';
$userForm = new Form_User();
if ($this->_request->isPost()) {
if ($userForm->isValid($_POST)) {
$userModel = new Model_User();
$newUserRow = $userMode->createUser(
$userForm->getValue('email'),
$userForm->getValue('password'),
$userForm->getValue('url'),
$userForm->getValue('responsable'),
$userForm->getValue('role')
);
$user_id = newUserRow->id;
$checkBoxValues = $userForm->getValue('pais');
// $checkBoxValues should be an array where keys are option names and
// values are values. If checkbox is not checked, than the value = 0;
// At this moment I'm not 100% sure of the real nature of the 'pais' value,
// but this is only an example.
// I also assume that the values of the checkboxfields correspond to IDs in
// 'pais'.
foreach ($checkBoxValues as $key => $pais_id) {
if (intval(pais_id) > 0) {
// if language was checked
// do insert into user_has_pais having $pais_id and $user_id.
}
}
return $this->_forward('list');
}
}
$userForm->setAction('/user/create');
$this->view->form = $userForm;
}
You could also put all of this in transaction if you want.
Hope this helps, or at least you point you in the right direction.