This might be a bit strange, but I'll try to explain. Basically I have a table containing users and a table containing customers. Users have permission to look into the data of only certain customers. So I figured I would make a separate table for user permissions, taking the user ID and the customer ID as foreign keys and having one row per customer/user permission.
When the admin adds a new user to the database using a class called UserForm (posted shortened below for reference), which uses Zend\Form, I want to also display all the customers next to the form as buttons that can be selected to be added as permissions. Now, I thought I would do that by having a JavaScript array that appends or removes the customer IDs if they're selected/deselected, then passing that array to the form as a hidden value and finally looping through the array inserting a row into the permissions table for each customer ID in the array, and taking the user ID that's been created as well. I'm not sure if this is the best way to do it, but it's the best I could come up with.
Hope that's at least slightly understandable. So, I have one form, but I want to insert into two different tables. My question, I guess, is how do I pass the array to the form as a value? And how do I insert into not only the users table, but also the permissions table, when the saveUser() method is called (I'll post that below too). Also, is this a really weird way of doing it that I'm being unnecessarily difficult about? I'd love to hear if there's a much easier way.
My UserForm class:
namespace Admin\Form;
use Zend\Form\Form;
class UserForm extends Form
{
public function __construct($name = null)
{
parent::__construct('user');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'userId',
'attributes' => array(
'type' => 'Hidden',
),
));
$this->add(array(
'name' => 'activated',
'attributes' => array(
'value' => 1,
'type' => 'Hidden',
),
));
$this->add(array(
'name' => 'username',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Username:',
),
));
$this->add(array(
'name' => 'firstname',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'First name:',
),
));
$this->add(array(
'name' => 'lastname',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Last name:',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
}
My saveUser() method
public function saveUser(User $user)
{
$data = array(
'firstname' => $user->firstname,
'lastname' => $user->lastname,
'username' => $user->username,
'activated' => $user->activated,
);
$userId = (int)$user->userId;
if ($userId == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getUser($userId)) {
$this->tableGateway->update($data, array('userId' => $userId));
} else {
throw new \Exception('User ID does not exist');
}
}
}
One method is to use Form Fieldsets. A form can have multiple Fieldsets, and each Fieldset can be bound to a different entity.
These are useful when you have a one to one relationship between the entities
You would then create teo entities, for example a User entity (as you already have) and a new entity to represent your Permission.
You would create a Feildset for each and bind the objects to the fields sets. (UserFieldSet and PermissionFieldset for example)
checkout the section on Form Fieldsets:
http://zf2.readthedocs.org/en/latest/modules/zend.form.advanced-use-of-forms.html
If you have a one to many relationship, ie. One User can have Many Permissions, then you would be better off looking at form Collections:
http://zf2.readthedocs.org/en/latest/modules/zend.form.collections.html
there's an example of dynamically adding new rows for a one to many relationship too.
Related
I am using PHP Zendframework to build forms. I have service object that i need want to use to populate my ServiceEditForm.php. But in this service form i have Object of "Billing", "Subscription" and array of object "Commands". Below is my implementation of Service class.
class Service{
public $service_id;
public $ServiceName;
public $TelecomOperator;
public $SubMethod;
public $Provider;
public $active;
public $billingType;
public $subscriptionPlan;
public $commands;
function exchangeArray(array $data);}
I want to bind the object of Service class to my Edit form which used subscription, billing and commands related data as fieldsets. I am able to populate service values in form using bind but not other objects. here is my form implementation
class ServiceEditForm extends Form{
public function __construct($name = null)
{
parent::__construct('Edit Service');
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/form-data');
//here i have other fields that belongs to service object
$this->add( array(
'name' => 'billingType',
'type' => 'Services\Form\BillingTypeFieldset',
'options' => array(
'label' => 'Billing Type',
),
));
$this->add( array(
'name' => 'subscriptionPlan',
'type' => 'Services\Form\SubscriptionPlanFieldset',
'options' => array(
'label' => 'Subscription Plan',
),
));
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'commands',
'options' => array(
'label' => 'commands',
'count' => 2,
'should_create_template' => true,
'allow_add' => true,
'target_element' => array(
'type' => 'Services\Form\CommandFieldset',
),
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Save'
),
));
}
}
As I said I am not able to populate fieldsets with bind within form with this implementation. Any suggestion will be appreciated.
Although I have already answer the question after looking up for possible solutions but Hydrator Implementations given in this link is also useful in explaining the very basics that one should read before using it. My bad i didn't went for full-throttled study before implementing fieldsets.
http://framework.zend.com/manual/current/en/modules/zend.stdlib.hydrator.html
This url explain possible implementation of hydrators that can deliver you very easy binding solution for your class.
I have a project to create a flexible information system. In this project I use a relational database (MySQL) and the Yii framework. Sometimes I have objects that can collect different information according to the id of the objecttype.
Basically, I have an object, which has an objecttype. In the objecttype table i have an info field which will contain a jSON with the description of the additional fields that I will require from the user at the moment of the new object creation.
http://www.bedoya.co/screenshots/object-objecttype-relation.png
Ok, now, with PHP I will collect the contents from objecttype_info (stored there as a jSON) and I will generate an array similar to this one:
<?php
$x = array(
'name' => 'Cool name to put in the fieldset label of this object type',
'fields' => array( // List of additional fields that describe this object
'field1' => array(
'label' => 'Field1 label',
'type' => 'text',
'htmlOptions' => array(
'class' => 'field1-class'
'id' => 'field1-id'
'required' => true
)
),
'campo2' => array(
'label' => 'Field2 label',
'type' => 'number',
'htmlOptions' => array(
'class' => 'field2-class'
'id' => 'field2-id'
'required' => false
)
),
)
);
Now, I get the required values with the easy function:
<?php
$x = ObjectType::model()->findByPk( $objecttype_id )->attributes[ 'objecttype_info' ];
?>
I don't know how to set the validation rules for the fields obtained from the objecttype. Any ideas? Am I doing this right?
In my form model I have this:
class UpdateForm extends Form {
public function __construct($name = null) {
parent::__construct('updateForm');
$this->setAttribute('method','post');
$this->add(array(
'name' => 'response',
'attributes' => array(
'type' => 'textarea',
),
'options' => array(
'label' => 'Response',
),
));...
In my view I was doing this:
$form->get('response')->setAttributes(array(
'class' => 'form-control',
'placeholder' => '--- Enter your response here ---'
));
I found I can set the class of a specific form input in my Form model by just doing:
$this->add(array(
'name' => 'response',
'attributes' => array(
'type' => 'textarea',
'class' => 'fart',
),...
But now I wonder if this is wise. Should I do this in the view or does it matter (assuming I am trying to adhere to MVC best practices)
Both of the options are valid.
I am not sure which one best fits the MVC approach but here's what I do. If I am working in a team and if someone else is handling the design of the application, I will add these CSS classes in the view. So the designer can change them if he/she wants to.
If I am most likely to work with a developer I assign the CSS classes in the model. And leave a comment in the view pointing out the location of the file where the classes are assigned.
Hope this help.
I am having a bit of a problem with saveAll, however I have a feeling what I am trying to do isn't possible but would be interested to see what people think.
The models in question are
League
Team
User
The relationships are as follows:
LEAGUE
One league can have many teams, however the league is owned by one user (the admin).
var $belongsTo = 'User';
var $hasMany = 'Team';
TEAM
Each team can be in one league and be owned by one user.
var $belongsTo = array('User', 'League' => array('counterCache' => true));
USER
Each user can be admin for multiple leagues and also have multiple teams
var $hasMany = array('League', 'Team');
I have a form where by a user can create a new league, create a team to add to the league and also register. The data that gets posted back to CakePHP is as follows:
array(
'League' => array(
'name' => 'Valid League Name',
'max_teams' => '10'
),
'Team' => array(
array(
'name' => 'Valid Team Name'
)
),
'User' => array(
'password' => 'password1',
'firstname' => 'Firstname',
'lastname' => 'Lastname',
'email' => 'test#example.com',
'confirm_password' => 'password1'
)
);
Now assuming this all passes validation and this is the first data entered in to the database I would expect the following to be returned from the saveAll operation that I am using:
array(
'League' => array(
'id' => 1,
'name' => 'Valid League Name',
'max_teams' => '10',
'user_id' => 1
),
'Team' => array(
array(
'id' => 1,
'name' => 'Valid Team Name',
'league_id' => 1,
'user_id' => 1
)
),
'User' => array(
'id' => 1,
'password' => 'password1',
'firstname' => 'Firstname',
'lastname' => 'Lastname',
'email' => 'test#example.com',
'confirm_password' => 'password1'
)
);
What is happening however is that the user_id field in the Team array isn't getting populated and it just coming back instead as null. What I am guessing is that CakePHP can't be sure that the team and the user that have just been created are necessarily related to one another so haven't created the association between the two.
At the moment, within the controller where the save is being made (I am saving through the League model $this->League->saveAll()) I am manually getting the user_id once everything has been saved and resaving the team with the new user_id. Is there anything I can do to get Cake to realise that the two are associated to the saveAll function does everything I need? I have tried using saveAll() with the deep option enabled and this also has no affect.
I'm trying to work out how to filter empty records from a form collection. With my application I have 2 entities, Competition and League. A competition may have zero or more Leagues.
So I create a Competition form (CompetitionForm), a Competition fieldset (CompetitionFieldset) and a League fieldset (LeagueFieldset).
The CompetitionFieldset is added to the CompetitionForm, and the CompetitionFieldset uses Zend\Form\Element\Collection to allow the user to add 1 or more Leagues. I've added the current code for each class below.
By default, I want to display input fields for 3 leagues within a competition, so within the CompetitionFieldset, when I add the Zend\Form\Element\Collection item, I set the count option to 3.
But if a user doesn't supply any data for the leagues, I want to ignore them. At present, three empty associated leagues are created within my database.
If I set an InputFilter on the LeagueFieldset to make the name field required for example, then the form won't validate.
I should maybe also mention that I'm using Doctrine2 to model my entities and hydrate my forms etc.
I'm sure I could make it work with some additional code on my models, or even in my Controller where I process the form, but I'm sure there is a neater solution maybe using Filters.
If anyone could point me in the right direction it would be much appreciated.
Many thanks in advance for any help you can provide.
:wq
familymangreg
My CompetitionForm
use Kickoff\Form\AbstractAdminForm;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Stdlib\Hydrator\ClassMethods;
class CompetitionForm extends AbstractAdminForm
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct($objectManager, 'competition-form');
$fieldset = new CompetitionFieldset($objectManager);
$fieldset->setUseAsBaseFieldset(true);
$this->add($fieldset);
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit',
'id' => 'submitbutton',
),
));
}
}
My CompetitionFieldset
use Kickoff\Form\AbstractFieldset;
use Kickoff\Model\Entities\Competition;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
class CompetitionFieldset extends AbstractFieldset
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct($objectManager,'Competition');
$this->setHydrator(new DoctrineHydrator($this->objectManager,'Kickoff\Model\Entities\Competition'))
->setObject(new Competition());
$this->setLabel('Competition');
$this->add(array(
'name' => 'name',
'options' => array(
'label' => 'Competition name (e.g. Premier League)',
),
'attirbutes' => array(
'type' => 'text',
),
));
$this->add(array(
'name' => 'long_name',
'options' => array(
'label' => 'Competition long name (e.g. Barclays Premier League)',
),
'attirbutes' => array(
'type' => 'text',
),
));
$leagueFieldset = new LeagueFieldset($objectManager);
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'leagues',
'options' => array(
'label' => 'Leagues',
'count' => 3,
'should_create_template' => true,
'allow_add' => true,
'target_element' => $leagueFieldset,
),
));
}
}
My LeagueFieldset
use Kickoff\Form\AbstractFieldset;
use Kickoff\Model\Entities\League;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\InputFilter\InputFilterProviderInterface;
class LeagueFieldset extends AbstractFieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct($objectManager,'League');
$this->setHydrator(new DoctrineHydrator($this->objectManager,'Kickoff\Model\Entities\League'))
->setObject(new League());
$this->setLabel('League');
$this->add(array(
'name' => 'name',
'options' => array(
'label' => 'League name (e.g. First Qualifying Round)',
),
'attirbutes' => array(
'type' => 'text',
),
));
$this->add(array(
'name' => 'long_name',
'options' => array(
'label' => 'League long name (e.g. UEFA Champions League First Qualifying Round)',
),
'attirbutes' => array(
'type' => 'text',
),
));
}
public function getInputFilterSpecification()
{
return array(
'name' => array(
'required' => true,
)
);
}
}
You need to get data from request before you pass it to EntityManager, that's for sure. Just add your own validation to filter empty records. You can also provide javascript filters that will catch submit form event and delete empty fields before submitting it.