i'm creating a application in which i need to populate data in select element from a db table.
i need to populate user roles from db
my form code is
$this->pass2->addValidator('Identical', false, array('token' => 'pass1'));
$this->addElement('select', 'userrole', array(
'class' => 'form-control',
'required' => true,
'multiOptions' =>
));
what should i do with multi options ?,
is there any way to load data from db in element using controller ,please helpme
thanks
What I have done in the past is to pass the db-adapter (or a model that knows how to do the required db query) to the form as a constructor parameter.
Something like this:
class Application_Form_MyForm extends Zend_Form
{
protected $db;
public function __construct($db)
{
$this->db = $db;
// Don't forget to call the parent __construct. Ultimately
// it is the parent __construct() that calls your init()
// method that adds your elements
parent::__construct();
}
public function init()
{
// Create your form elements
// $this->addElement('text', 'my_text_field'); // etc
// Now your select field...
$this->addElement('select', 'my_select', array(
'multiOptions' => $this->buildMultiOptions(),
'validators' => array(
// blah, blah
),
);
}
protected function buildMultiOptions()
{
$select = $this->db->select()
->from('my_table', array(
'my_value_column',
'my_display_column'
))
->order(array(
'my_display_column ASC',
));
$results = $this->db->query($select)->fetchAll();
$return = array();
foreach ($results as $row) {
$return[$row['my_value_column']] = $row['my_display_column'];
}
return $return;
}
}
Then in the controller action, when you instantiate your form, you grab the db-adapter and pass it in as a constructor parameter:
$db = $this->getInvokeArg('bootstrap')->getResource('db');
$form = new Application_Form_MyForm($db);
// Then process your form as usual
on case with is necessary populate options outside form class.
$form->getElement( 'ele_name' )
->setConfig(new Zend_Config( array(
'multiOptions' => array('option1','option2') )
)));
Related
Hi I am trying to update a record in my database, It is a reservation that the user can update some or all of the fields and after I press submit it redirects me to the page I need but no changes happen in the database.
Model
public function res_form_input(){
$newDate = date("Y-m-d",strtotime($this->input->post('re_date')));
$newTime = date("H:i", strtotime($this->input->post('re_time')));
$data = array(
'num' => $this->input->post('num'),
'location' => $this->input->post('location'),
'diners' => $this->input->post('diners'),
're_date' => $newDate,
're_time' => $newTime,
'phonenumber' => $this->input->post('phonenumber'),
'fullname' => $this->input->post('fullname'),
);
return $data;
}
public function update_res($id){
$data = $this->res_form_input();
// $this->db->set('$data');
$this->db->where('id', $id);
$this->db->update('tables', $data);
}
Controller
public function edit() {
echo $id = $this->session->flashdata('reservation_id');
$this->Hosting_model->update_res($id);
redirect(base_url("/hosting/tableMap"));
}
I would like to create a menu in new CakePHP 3.0 and I found that using cells might be a good way. So let's say I created UserMenuCell
class UserMenuCell extends Cell {
protected $_validCellOptions = [];
public function display() {
$menu = [];
$menu[] = $this ->menu( __('Dashboard'), array( 'controller' => 'Users', 'action' => 'dashboard' ), 'fa-dashboard', [] );
if( $this -> Auth -> isAuthorized(null, ??? ))
$menu[] = $this ->menu( __('Barcodes'), array( 'controller' => 'Barcodes', 'action' => 'index' ), 'fa-table', [] );
$this -> set ( 'menu', $menu );
}
private function menu( $title, $url = [], $icon, $submenu = [] ) {
return ['title' => $title, 'url' => $url, 'icon' => $icon, 'submenu' => $submenu]; }
}
But I want to display Barcodes item only when current user is authorized to manage barcodes. How can I do it? I can't even access $this -> Auth to get current user.
In my cell's template is everything OK. I just need to create this nested array for menu.
According to Cookbook, the session is available from within Cells.
class UsermenuCell extends Cell
{
public function display()
{
var_dump($this->request->session()->read('Auth'));
}
}
Like this you could read the needed informations in your cell display function.
and if you pass the session variable?
<?= $this->cell('userMenu', $this->Session->read('Auth')); ?>
I think the problem is solved:
I can make controller to have static method for example static public function _isAuthorized($user, $request) which would handle the authorization logic (so every controller controls only its own permissions).
And then I can just call from anywhere for example PostsController::_isAuthorized($user, ['action' => 'add']). This should solve all problems I guess.
Also good point is to pass $this -> Auth -> user() into view, so it can be used in Cells (through parameter).
src/Controller/AppController.php
public function beforeFilter(Event $event) {
$this -> set('user', $this -> Auth -> user());
}
src/View/Cell/MenuCell.php
use App\Controller\PostsController; // Don't forget to use namespace of your Controller
class MenuCell extends Cell {
public function display($user) {
$menu = [];
if (PostsController::_isAuthorized($user, ['action' => 'add'])) // In that method you must handle authorization
$menu[] = ['title' => 'Add post', 'url' => array('controller' => 'Posts', 'action' => 'add')];
$this -> set ('menu', $menu); // Handle this in Template/Cell/Menu/display.ctp
}
}
src/Template/Cell/Menu/display.ctp - just to show how to render menu
<ul>
<?php foreach($menu as $item) {
echo '<li>' . $this -> Html -> link ($item['title'], $item['url']);
} ?>
</ul>
src/Template/Layout/default.ctp - render menu in main layout
<?= $this -> cell('Menu', array($user)) /* This is the user passed from beforeFilter */ ?>
Then you can play with isAuthorized methods. For example you can edit your AppController. Always when CakePHP calls isAuthorized function it will be redirected to YourNameController::_isAuthorized() static method (if exists).
src/Controller/AppController.php
public function isAuthorized( $user ) {
$childClass = get_called_class();
if(method_exists($childClass, '_isAuthorized'))
return $childClass::_isAuthorized($user, $this -> request);
return static::_isAuthorized($user, $request);
}
static public function _isAuthorized($user, $request)
{
if ($user['role'] == 'admin')
return true;
return false; // By default deny any unwanted access
}
This is an example of your controller. You can specify only static _isAuthorized($user, $request) method, because for purposes of CakePHP default behavior it will be called from AppController::isAuthorized (see code above).
src/Controller/PostController.php
static public function _isAuthorized($user, $request)
{
$action = ($request instanceof Cake\Network\Request) ? $request -> action : $request['action'];
if($action == 'add' && $user['role'] == 'CanAddPosts')
return true;
return parent::_isAuthorized($user, $request);
}
As you can see I made $request to accept an array or Cake\Network\Request object. That's because CakePHP call it with Request object but when I call it I don't need to create this object, since my parameters are easy (see code above MenuCell.php).
Of course you can now do more complex logic like user can have more roles separated by comma and you can explode this and check if user has permission by in_array.
Now it's really up to you what is your logic behind permissions. Every controller can handle it's own permission managing while you can always access these permissions with every user and every page request.
I am trying to make a login by getting/authorizing only one input *user_number* (Not username - password).
I made my current login page with the following way:
Cakephp2.x simple login
Any help plz!
Keep it simple
If you only have one way of identifying users, the simplest (and therefore recommended) way to identify users would be to define your own login function. e.g.:
public function login() {
if ($this->request->is('post')) {
$number = $this->request->data['User']['user_number'];
$user = $this->User->findByUserNumber($number);
if ($user && $this->Auth->login($user)) {
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Session->setFlash(__('User %d doesn\'t exist', $number), 'default', array(), 'auth');
}
}
}
Note that this varies very little from the standard way of logging a user in with Cake 2.x
Create a Custom Authentication object
Create a Custom Authentication object that authenticates uses by user-number only;
Creating Custom Authentication objects
app/Controller/Component/Auth/UserNumberAuthenticate.php
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
class UserNumberAuthenticate extends BaseAuthenticate {
public function authenticate(CakeRequest $request, CakeResponse $response) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
if (
empty($request->data[$model])
|| empty($request->data[$model][$fields['username']])
) {
return false;
}
return $this->_findUser($request->data[$model][$fields['username']]);
}
/**
* Find a user record via his user-number/identifier
*
* #param string $usernumber The user-number/identifier.
* #return Mixed Either false on failure, or an array of user data.
*/
protected function _findUser($usernumber) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
$conditions = array(
$model . '.' . $fields['username'] => $usernumber,
);
if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}
$result = ClassRegistry::init($userModel)->find('first', array(
'conditions' => $conditions,
'recursive' => $this->settings['recursive'],
'contain' => $this->settings['contain'],
));
if (empty($result) || empty($result[$model])) {
return false;
}
$user = $result[$model];
unset($result[$model]);
return array_merge($user, $result);
}
}
Then specify that you want to use your custom authentication object
Inside your AppController:
public $components = array(
'Auth' => array(
'authenticate' => array(
'UserNumber' => array(
'userModel' => 'User',
'fields' => array('username' => 'user_number')
)
)
)
);
I have added translate behaviour to a model, the model comes here
App::uses('AppModel', 'Model');
class Category extends AppModel
{
public $hasMany = "Product";
public $validate = array(
'name' => array(
'rule' => 'notEmpty'
)
);
public $actsAs = array(
'Translate' => array(
'name','folder','show'
)
);
public $name = "Category";
public $translateModel = 'KeyTranslate';
}
And heres the controller for updating the model
public function admin_edit_translate($id,$locale)
{
$this->Category->locale = $locale;
$category = $this->Category->findById($id);
if ($this->request->is('post') || $this->request->is('put')) {
$this->Category->id = $id;
if ($this->Category->save($this->request->data)) {
$this->Session->setFlash('Category translate has been updated');
//$this->redirect(array('action' => 'edit',$id));
} else {
$this->Session->setFlash('Unable to update category');
}
}
if (!$this->request->data) {
$this->request->data = $category;
}
}
My Problem is that i have a name field in the categories database and when i update or create a new translation it gets updated with the translated value. How do i avoid that
You must use Model::locale value to set code language for save in database
This happens because the TranslateBehavior uses callbacks like beforeSave and afterSave to save translated content, so it needs to let the model's save operation continue and thus will contain the last translated content.
You could get around this by tricking the TranslateBehavior into thinking the model is saving something by calling the beforeSave and afterSave like this:
$Model = $this->Category;
$Model->create($this->request->data);
$Model->locale = $locale;
$beforeSave = $Model->Behaviors->Translate->beforeSave($Model, array(
array(
'callbacks' => true
)
));
if($beforeSave) {
$Model->id = $id;
$Model->Behaviors->Translate->afterSave($Model, true);
}
This way the translation will be saved and the main table will be left untouched. Might not be the best way to save translations though. Why do you need to leave the main table untouched?
Callback Behavior::beforeSave is before Model::beforeSave...
but, the simplest way to modify data in Model::beforeSave before Behavior::beforeSave before realy saving is:
$this->Behaviors->Behavior_Name->runtime[Model_Name]['beforeSave'][Field_Name] = '...';
I'm building a form which contains a category field. I need a choice list to do that, but I don't find out how to fill this choice list with the several categories stored in the database.
public function buildForm(FormBuilder $builder, array $options) {
$builder->add('item', 'text', array('label' => 'Item'));
$builder->add('category', 'choice', array(
'choices' => ???,
'label' => 'Category'
));
}
How can I get the categories from the database?
(I can't seem to access $this->getDoctrine() inside this class.)
Use type entity instead of choice
$builder
->add('entity_property', 'entity', array(
'class' => 'Namespace\\To\\Entity',
'query_builder' => function(EntityRepository $repository) {
return $repository->createQueryBuilder('q')
->where('q.a_field = yourvalue');
}
));
Edit:
Two ways for using custom parameters in your query. In both situations, the parameters are injected from outside, so your FormType don't need any references to the session or request objects or whatever.
1- Pass required parameters to your constructor
class TaskType extends AbstractType
{
private $custom_value;
public function __construct($custom_value) {
$this->custom_value = $custom_value;
}
// ...
}
in your buildForm() you must copy the value to local variable and make it available for the query_builder callback:
public function buildForm(/*...*/) {
$my_custom_value = $this->custom_value;
// ...
'query_builder' => function(EntityRepository $repository) use ($my_custom_value) {
return $repository->createQueryBuilder('q')
->where('q.a_field = :my_custom_value')
->setParameter('my_custom_value', $my_custom_value);
}
// ...
}
2- use the $options parameter of the buildForm method.
First you have to define a default value by overriding getDefaultOptions:
public function getDefaultOptions(array $options)
{
return array(
'my_custom_value' => 'defaultvalue'
);
}
Then you can pass it from your controller in the third argument of the createForm method.
$this->createForm(new YourFormType(), $entity, array('my_custom_value' => 'custom_value'));
Now the value should be available through the $options parameter of youru buildForm method. Pass it to the callback as described above.
In Symfony 2.1
You now have to use the OptionsResolverInterface within the setDefaultOptions method. Here is the code you would have to use if you wanted to retrieve the options (using the same example as the accepted answer)
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
public function buildForm(FormBuilderInterface $builder, array $options){
parent::buildForm($builder, $options);
$my_custom_value = $options[custom_value];
// ...
'query_builder' => function(EntityRepository $repository) use ($my_custom_value) {
return $repository->createQueryBuilder('q')
->where('q.a_field = :my_custom_value')
->setParameter('my_custom_value', $my_custom_value);
}
// ...
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'my_custom_value' => 'defaultvalue'
));
}
You still pass the options in the same way:
$this->createForm(new YourFormType(), $entity, array('my_custom_value' => 'custom_value'));