How to dynamically populate list box from database?
Please Provide some examples in zend framework.
Say if you have a table called Test and a corresponding model for it named Test,
class Test extends Zend_Db_Table {
protected $_name = "Test";
function getLisItems() {
$select = $this->getAdapter()->select()->from($this->_name, array(
'key' => 'column1_key',
'value' => 'column2_value'
));
return $this->getAdapter()->fetchPairs($select);
}
}
In your controller action or view, have the following code.
$t = new Test();
$list = new Zend_Form_Element_Select('list');
$list->setLabel('Select your item: ')
->addMultiOptions($t->getLisItems());
Now your list box will be populated with items from the database.
Related
I am struggling to add sort functionality on one of my member summary fields in admin.
I have extended the Silverstripe member class using:
class MyMemberExtension extends DataExtension
I have added a few fields to the default gridfield in admin:
private static $db = array(
'Organisation' => 'Varchar(100)'
);
private static $summary_fields = array(
'FirstName' => 'First Name',
'Surname' => 'Surname',
'Email' => 'Email',
'OrganisationName' => 'Organisation Name',
'LastVisited' => 'Last Visited',
'NumVisit' => 'Num Visits'
);
private static $casting = array(
'OrganisationName' => 'Varchar(100)'
);
public function getOrganisationName() {
return $this->owner->Organisation;
}
...and that all works nicely.
However, only the core fields like LastVisited are giving me sort arrows on the column headers.
I'm currently stuck as to how to implement the sort on my Organisation field. I tried adding :
public function getCMSFields()
{
$fields = parent::getCMSFields();
$grid = $fields->dataFieldByName('Organisation');
$gridConfig = $grid->getConfig();
$gridConfig->addComponent(new GridFieldSortableHeader());
return $fields;
}
public function getEditForm($id = null, $fields = null) {
$form=parent::getEditForm($id, $fields);
$model = singleton($this->modelClass);
// add sorting if we have a field for...
if (class_exists('GridFieldSortableRows')
&& $model->hasField('Organisation')
&& $gridField=$form->Fields()->dataFieldByName($this->sanitiseClassName($this->modelClass))) {
if($gridField instanceof GridField) {
$gridField->getConfig()->addComponent(new GridFieldSortableRows('Organisation'));
}
}
return $form;
}
...to my class, but I'm not convinced these are even being called, as even if I just return null from these two functions nothing changes.
I have found a few answers that deal with extensions to ModelAdmin, but not for the core Member list. Thanks!
First of all, I'm not sure why you chose to have a getter named OrganisationName, where you could just as well use Organisation directly? That being said, I think your question is valid and might apply to different scenarios and/or field-types.
The Form-field that is being used to edit members is the Members GridField within SecurityAdmin. Luckily, there's an extension hook (updateEditForm) to modify the form fields of SecurityAdmin.
So in order to modify the sorting of the Members GridField, create an Extension like the following:
<?php
class MemberAdminExtension extends Extension
{
public function updateEditForm(Form $form)
{
/** #var GridField $memberGridField */
if ($memberGridField = $form->Fields()->dataFieldByName('Members')) {
/** #var GridFieldSortableHeader $sortHeader */
if ($sortHeader = $memberGridField->getConfig()->getComponentByType('GridFieldSortableHeader')) {
// Map OrganisationName to the Organisation field
$sortHeader->setFieldSorting([
'OrganisationName' => 'Organisation'
]);
}
}
}
}
And apply the extension via config to SecurityAdmin:
# Within _config/config.yml
SecurityAdmin:
extensions:
- MemberAdminExtension
After a dev/build your Member table should be sortable by Organisation Name as well…
I have a basic relation editor GridField, and I need to dynamically define/set the value of any objects added via that GridField, with data related to the GridField's context.
class Draw extends DataObject {
private static $has_many = array(
'Items' => 'Item'
);
}
When an Item is added via Draw's Items GridField, I need to define a value for use in Item::getCMSFields()
Some good suggestions in here: https://www.silverstripe.org/community/forums/data-model-questions/show/21517?start=7
You can work directly with the GridField's GridFieldDetailForm component, and set fields accordingly.
The code that worked for me is:
$config = GridFieldConfig_RecordEditor::create();
if($this->exists()) {
// Ensure that fields are generated with knowledge of the parent
$editComponent = $config->getComponentByType('GridFieldDetailForm');
$item = new Item();
$item->DrawID = $this->ID;
$editComponent->setFields($item->getCMSFields());
}
$items = new GridField('Items', 'Items', $this->Items(), $config);
$fields->addFieldToTab('Root.Main', $items);
You can then call Draw::get()->byID($this->DrawID) from Item::getCMSFields()
Pago, model exists in Yii. As I create relationships automatically?..
Example:
$pago = new Pago();
Now I want to show information:
echo $pago->iDTIPOTRAMITE->id;
It is assumed that the information must be loaded by default
thanks.
I think I found the solution here: model init()
With this method, set initial property values.
Example. Pago model.
public function init()
{
$documentos = DocumentacionT::model()->findAll(array(
'condition' => 'ID_TIPOSOLICITUD = :idTipo',
'params' => array(':idTipo' => 5)
));
$pagoDocumento = [];
foreach($documentos as $documento)
{
$pagoDocumento[] = new PagoDocumento();
}
$this->pagoDocumentos = $pagoDocumento;
}
I'm attempting to build an achievements system in my CakePHP app using CakeEvents. I've been using the following website for helping me put the Events together: http://martinbean.co.uk/blog/2013/11/22/getting-to-grips-with-cakephps-events-system/
In my app, achievements are called badges and can be awarded to users. These badges are awarded based on rules that link the badge to a Cake event.
So for example if a user creates a post, that will fire the Model.Post.add event which should check if any rules exist for that event, and if so do the parameters match up, and again if all checks out then award a badge connected to that rule to the user.
The schema comprises of the following tables:
users
id
username
password
posts
id
title
content
created
modified
user_id
badges
id
title
description
events
id
title
name
event_badges
id
event_id
badge_id
badge_users
id
badge_id
user_id
Hopefully that all makes sense. And here are the Models to show how they connect.
User.php
class User extends AppModel
{
public $name = 'User';
public $hasMany = array(
'Post', 'Badge'
);
public $belongsTo = array(
'BadgeUser'
);
}
Badge.php
class Badge extends AppModel {
public $hasMany = array(
'BadgeUser'
);
public $actsAs = array('Containable');
}
Event.php
class Event extends AppModel {
public $hasMany = array(
'EventBadge'
);
public $actsAs = array('Containable');
}
EventBadge.php
class ActionBadge extends AppModel {
public $belongsTo = array(
'Action', 'Badge'
);
public $actsAs = array('Containable');
}
BadgeUser.php
class BadgeUser extends AppModel {
public $belongsTo = array(
'Badge', 'User'
);
public $actsAs = array('Containable');
}
** Feel free to comment if you think the schema is incorrect to achieve what is being described in this question.**
So example badges might be:
Title: First Post, Description: Awarded for creating a post
Title: 10 Posts, Description: Awarded for creating 10 posts
Title: Editor, Description: Editing a post
Title: Deleter, Description: Deleting a post
And some example rules in the Events table:
Title: Add Post, Event Model.Post.add
Title: Edit Post, Event: Model.Post.edit
Title: Delete Post, Event: Model.Post.delete
Title: View Post, Event: Model.Post.view
So as you can see the Events are linked to the above Badges and the Events are called using the CakeEvents system.
Okay so when a person does something, let's say saves a new post, I have the following in the Post model:
public function afterSave($created, $options = array()) {
if ($created) {
$event = new CakeEvent('Model.Post.add', $this, array(
'id' => $this->id,
'data' => $this->data[$this->alias]
));
$this->getEventManager()->dispatch($event);
}
}
The first question is, how do I pass different events to the afterSave? As both Add and Edit methods in the controller would fire this...
And then I have a PostListener.php file in /app/Event
class PostListener implements CakeEventListener {
public function implementedEvents() {
return array(
'Model.Post.add' => 'postAdded',
'Model.Post.edit' => 'postEdited',
'Model.Post.view' => 'postViewed',
'Model.Post.delete' => 'postDeleted',
);
}
public function postAdded(CakeEvent $event) {
$this->Badge->awardBadge($badgeId, $userId);
}
public function postEdited(CakeEvent $event) {
}
public function postViewed(CakeEvent $event) {
}
public function postDeleted(CakeEvent $event) {
}
}
So the next question is how do I link the event listener back up to my Events table?
And then award the badge connected to that action? Noting that some will need to do extra checks like a user must of created 10 posts to achieve the 10 Posts badged and not just because they have created a post.
In the Badge.php model I have the following function to award badges:
public function awardBadge($badgeId, $userId) {
$controlFind = $this->BadgeUser->find(
'first',
array(
'conditions' => array(
'badge_id' => $badgeId,
'user_id' => $userId,
)
)
);
if(!$controlFind) {
$temp = array(
'BadgeUser' => array(
'badge_id' => $badgeId,
'user_id' => $userId,
'created' => date('Y-m-d H:i:s')
)
);
$collection[] = $temp;
return $this->BadgeUser->saveAll($collection, array('validate' => false));
}
}
So I need to run the code above from the listener when things match up with the DB rules. Just struggling to make it all stick together.
I think your database schema may be complicating things by having a notion of events. Personally, I’d have a badges table that stores badge title and description (and also image path if it’s needed). I’d then have an event listener that corresponds to each badge, so there will be some degree of manual labour involved.
So let’s think of a sample scenario. Let’s say a badge is awarded when a user posts a 100 times. So you’d have your Post model that fires an event when a post is saved:
<?php
App::uses('CakeEvent', 'Event');
class Post extends AppModel {
public function afterSave($created, $options = array()) {
$event = new CakeEvent('Model.User.afterSave', $this);
$this->getEventManager()->dispatch($event);
}
}
You can then create a corresponding handler:
<?php
// Event/BadgeListener.php
App::uses('CakeEventListener', 'Event');
App::uses('ClassRegistry', 'Utility');
class BadgeListener implements CakeEventListener {
public function implementedEvents() {
return array(
'Model.Post.afterSave' => 'afterSaveListener'
);
}
public function afterSaveListener(CakeEvent $event) {
// check number of posts
$this->Post = ClassRegistry::init('Post');
$count = $this->Post->find('count', array(
'Post.author_id' => $event->subject()->data[$event->subject()->alias]['author_id'];
));
// award badge
if ($count > 100) {
// TODO: check user does not already have badge
$this->BadgeUser = ClassRegistry::init('BadgeUser');
$this->BadgeUser->create();
$this->BadgeUser->set('badge_id', 'whatever_badge_id_actually_is');
$this->BadgeUser->set('user_id', $this->Auth->user('id')); // logged in user ID
$this->BadgeUser->save();
}
}
}
This is a rough example written off-the-cuff, but hopefully it should steer you in the right direction.
If there’s anything you want me to clear up, let me know and I’ll do my best.
The first question - differentiate between new post and edit
To differentiate between add and edit you need to pass along the $created parameter when you create your CakeEvent. Something like this:
public function afterSave($created, $options = array()) {
//NOTICE: it's afterSave now, since this will be called after edit or new
$event = new CakeEvent('Model.Post.afterSave', $this, array(
'created' => $created, //NOW you will know when you process the even if this was a new post or post edit
'id' => $this->id,
'data' => $this->data[$this->alias]
));
$this->getEventManager()->dispatch($event);
}
You should add to the data of your event all the data that you will need later on to process it and to match your rules. You can even add the model object itself, if you think you will need that to do some queries with it.
Second Question - how to link event processing to the Events table
In the Event listener you can use the ClassRegistry to get an instance of the Event model (and any other models you require). You can do your rules matching and once you have all the data you need you save the badge to the database.
Since you now know if it's an edit or a new post (from the event->data) you can take appropriate action.
The editor id I guess you can take it with the Auth component as being the logged in user. So when you have that you can use it to read what you need about the editor from the database.
To conclude: when you send your events, use the event data to pass all the information that you will need in the listener. Event can carry so much more information, not just their names and the fact that they were triggered. You can send and then look at the entire "context".
In the listener, make good use of the data you get from the event and of the currently logged in user ID or the post author, do the matching that you need to do and then save the badge for the appropriate user.
Hopefully this is what you were looking for :).
So I want to do the following:
I created a form class at /Form/Type/UserType.php
I have a table with a list of states (table named "states").
I want to show all of these states in a drop down menu.
What code should I use in the class UserType to show all the states?
I tried:
$request = new Request;
$conn = $request->get('database_connection');
$states = $conn->fetchAll('SELECT state_code, state_name FROM states');
$builder->add('state', 'choice', array(
'choices' => $states,
'required' => false,
));
but that gives me an error. Basically, I want to query all of the states from the table states, and create a drop down menu from all of these states.
You can create State entity, map it to states table and create a OneToMany relation with the User entity. Then in your UserType form $builder->add('state') should create dropdown field automatically. You also have to set data_class option to your User entity in getDefaultOptions method of UserType form.
#m2mdas has given you the correct object based answer. However, if all you really want to do is to store the state_code then what you have will almost work. You just need to get the connection right.
class MyType extends extends AbstractType
{
public function __construct($em) { $this->em = $em; }
public function buildForm(FormBuilder $builder, array $options)
{
$conn = $this->em->getConnection();
$statesx = $conn->fetchAll('SELECT state_code, state_name FROM states');
// Need to index for the choice
$states = array();
foreach($statesx as $state)
{
$states[$state['state_code']] = $state['state_name'];
}
$builder->add('state', 'choice', array(
'choices' => $states,
'required' => false,
));
...
// In your controller
$form = new MyType($this->getDoctrine()->getEntityManager());