Registration form with new fields related - fosuserbundle

i am trying to add fields to my registration form with FosUserBundle.
Adding normal fields to the Userclass like "name", "age" e.g is easy to do:
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder
->add('name')
;
}
public function getParent()
{
return 'fos_user_registration';
}
public function getName()
{
return 'acme_user_registration';
}
}
This is all working and the new fields are written to my database table.
But how do i add there a new FormType into the Registration type of the Fos Bundle, like:
A user can have an Address, which is related OneToMany.
I tried it with the following, by first creating the address class and giving him one user:
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="addresses")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
And then by adding addresses to the User class:
/**
* #ORM\OneToMany(targetEntity="Address", mappedBy="user")
*/
protected $addresses;
public function __construct()
{
parent::__construct();
// your own logic
$this->addresses= new ArrayCollection();
}
Adding the AddressType:
class AddressType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('state', 'text')
->add('city','text')
->add('zipcode', 'text')
->add('street', 'text');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\UserBundle\Entity\Address',
));
}
public function getName()
{
return 'address';
}
}
to the RegistrationFormType works and the fields are displayed in the browser:
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder
->add('name')
->add('addresses', new AddressType())
;
}
But when i try to submit the form with new data, i don't know how to say symfony that the address entered should be related to the User.
Im always getting the error:
"The form's view data is expected to be an instance of class Acme\UserBundle\Entity\Address, but is an instance of class Doctrine\Common\Collections\ArrayCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\Common\Collections\ArrayCollection to an instance of Acme\UserBundle\Entity\Address."
What am I doing wrong here?
Regards.

you're trying to add a collection as a single field, when you give a "data_class" you're saying "here this is the form for this entity", but as the error says the system has to manage a collection of forms each one related to a single entity, you need to data transform them to something he can manage in a simple (or prebuilt) way (look for DataTransformers)
or you can use the colletion field type and pass them the address form type
-- edited after the comment --
no, sorry i've missed that, you need an entity form type because you state that a user has one address (and many user can be mapped to the same address, i.e. a family), so there's no need of a collection, though you're in the owning side persisting the user you don't have to worry, if you say cascade persist in your mapping schema for the ManyToOne relation, Doctrine will store the address for you (or use an existing one in case of a matching one)
btw i was fuzzed by your sentence "A user can have an Address, which is related OneToMany." that's misleading, a user can have an address, which is related to a ManyToOne relation (many user can have an address), the address is in a oneToMany relation with users (an address is own by many users)

Related

CakePHP 4 - Unknown method "loadModel"

In a CakePHP 4 application I've added this to a model, src/Model/Table/SignUpsTable.php
public function initialize(array $config): void
{
parent::initialize($config);
// ...
$this->loadModel('EmailDomains');
}
I have a model called EmailDomains and the appropriate Table/Entity class files exist.
In a controller method I have the following:
// src/Controller/UsersController.php
public function initialize(): void
{
parent::initialize();
$this->loadModel('SignUps');
}
public function signUp()
{
// ...
}
When navigating to /sign-up in my browser it gives the following error:
Unknown method "loadModel" called on App\Model\Table\SignUpsTable
If I comment-out the loadModel code in SignUpsTable::initialize it clears this error but then other code I have in there won't work as it references $this->EmailDomains->...
That's because loadModel is in fact not a method in that class.
\TableRegistry::getTableLocator()->get('EmailDomains') will return the table object (which you can reference directly if you just need it once, or save in a local variable or class property)
Or if you use Cake\Datasource\ModelAwareTrait; in your particular table class, then the loadModel function should become available to you.

Get spring-data-mongodb to honor getter/setter without backing field?

I have a general-purpose POJO:
public class Thing {
private String name;
private String etc;
public String getName() {
return name;
}
// other getters and setters
}
I'm using Spring 4.3.9 and Spring-data-mongodb 1.10.4. I want to store instances of this POJO in Mongodb, but I have some constraints:
I can't add Spring annotations to the base class (but I can subclass Thing and annotate that).
I want to use the name field as the Mongodb unique ID (mainly to avoid creating a separate unique index for it).
I want to (redundantly) store the name field as an actual field named "name", so that other consumers of the collection don't have to know that "name" is stored in the _id.
I started out trying this:
public class SpringThing extends Thing {
#Id
#Override
public String getName() {
return super.getName();
}
#Override
public void setName(String name) {
super.setName(name);
}
}
This causes spring to use the value of name for _id, but of course it doesn't store a field named "name" in Mongodb. The documentation says that spring will use a "property or field" named "id" or annotated with #Id. So I tried defining a redundant getter/setter which accesses the name field:
public class SpringThing extends Thing {
#Id
public String getId() {
return super.getName();
}
public void setId(String id) {
super.setName(id);
}
}
Unfortunately, spring ignores getId and setId here, and stores the object with an autogenerated ID. I also tried creating redundant getters/setters annotated with #Field("name"), but spring seems to ignore any getter/setter pair without an actual field.
Adding an actual ID field and storing a copy of the name there does work:
public class SpringThing extends Thing {
#Id
private String id;
#Override
public void setName(String id) {
this.id = id;
super.setName(id);
}
}
But it requires defining a pointless field named "id".
Is there a more reasonable way to get what I want? Is what I'm trying to do reasonable to begin with?
Thanks to a hint by #mp911de, I ended up creating a subclass of Thing that looks like this:
#TypeAlias("thing")
#Document(collection = "things")
public class SpringThing extends Thing {
#Id
#AccessType(Type.PROPERTY)
#JsonIgnore
public String getId() {
return super.getName();
}
public void setId(String taskName) {
super.setName(taskName);
}
}
The #TypeAlias annotation overrides the name which spring would use for the type, to cover up the fact that I've created a subclass just to add annotations.
#Id says that this is the getter for _id.
#AccessType says to access this field through the getter and setter rather than by directly accessing the field. This is what I needed; without it, spring looks for a private member variable named something like id.
#JsonIgnore is the Jackson (JSON library that we're using) annotation to prevent including the id field when serializing these objects to JSON.

cakephp use record values in afterDelete

I am using the soft delete plugin for my EmployeesTable.php in CakePHP 3.0.
When I soft delete an employee I wish to update their associated user table with $user->set('active', false); within the afterDelete()
My problem is getting the user_id used in the employees table into the afterDelete()
I have even tried to just the id of the employee deleted and do a find on that but the examples I have seen using the $this->id return and error Table "App\Model\Table\EmployeesTable" is not associated with "id" from the beforeDelete.
EmployeesTable.php
public function afterDelete( ) {
$user = $this->Users->get($this->user_id);
$user->set('active', false);
$this->Users->save($user);
}
I have also tried catching $this->id in beforeDelete() and passing it to the afterDelete() but again get the error Table "App\Model\Table\EmployeesTable" is not associated with "id"
private $deletedUserId;
public function beforeDelete($event, $entity, $options) {
$this->deletedUserId = $entity->user_id;
}
public function afterDelete( ) {
$user = $this->Users->get($this->deletedUserId);
$user->set('active', false);
$this->Users->save($user);
}
I haven't used Cake 3 yet, but I've always solved this in Cake 2.x using that last try of yours. Problem is, $this->id is not a safe variable to use, as it already exists in the model and is modified during database interactions.
I'd say you just need to have a private $deletedId; in your model, set it in beforeDelete() and get it in afterDelete(). You can even unset it right after using it, just in case.
I'm not sure but I think you can use the Event object with entities like:
public function afterDelete(Event $event) {
$entity = $event->data["entity"];
Log::debug("all data: " . $entity);
}
This will log a array inside the debug.log file, with all the data of the deleted user.

Symfony2 array of custom objects into form fields

I get some data from an API inside my Symfony 2 application using Guzzle. Those data are properly mapped into my model. The model is a Contact object with some properties. One of those property is an array of ContactMethod done like this
/**
* #SerializedName("methods")
* #Type("array<My\Bundle\Model\ContactMethod>")
*/
private $methods;
The ContactMethod object has just two properties: type and value
class ContactMethod {
/**
* #SerializedName("type")
* #Type("string")
*/
private $type;
/**
* #SerializedName("value")
* #Type("string")
*/
private $value;
... setters and getters ...
I've created a ContactType with its buildForm function in order to display all the property of Contact in a form. But when it comes to display the methods property I would like to have a TextInput for each of the ContactMethod and that input should take the type as label and the value as value.
class ContactType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options = array())
{
$builder
->add(...all the other simple fields...)
->add(...what shall I add here ? )
I also need this to work in the opposite way: when all the text inputs are filled and submitted, the fields has to be packed together into an array of ContactMethod so I can reserialize and send back the data to the API.
I've tried to play around with custom form types and also Data Transformers but I could not find a solution.
Your Contact object is mapped onto one ContactType, so just add a property methods and its type (e.g.) "method_list" if it's declared as a service or just new MethodListType().
The list is dynamic, so you have to write your own buildView method for the new Type.

Laravel Relationships (user-upload)

I get the following errors when i am trying to save the data with the file upload function because I have declared a new uploader_id to my table which should get its value from the relationship I wrote in the model.
Illuminate \ Database \ QueryException
SQLSTATE[HY000]: General error: 1364 Field 'uploader_id' doesn't have a default value (SQL: insert into `assets` (`filename`, `title`, `body`, `filepath`, `extension`, `realpath`, `mime`, `updated_at`, `created_at`) values (users.mov, New, dummy text data. , /uploads/User Test/2014-03-04_00:48, mov, /private/var/tmp/phpHDpmEI, video/quicktime, 2014-03-04 00:48:59, 2014-03-04 00:48:59))
In my models I defined the following
User Model: where assets its the table name for the uploads table in database
public function assets() {
return hasMany('assets');
}
Upload Model:
public function user() {
return belongsTo('user', 'uploader_id');
}
I have tried in my controller where i am using Upload::create(array()) function to post the data to the database, to add another parameter called 'uploader_id' => Auth::user()->id; but none of this work.
What is the best way to pass the uploader_id to the form each time the user uploads a file ?
That's what events are for:
class Asset extends Eloquent {
public static function boot()
{
static::creating(function($model)
{
$model->uploader_id = Auth::user()->id;
});
}
}
Also your relationships should reference their class -
return $this->hasMany('Asset');

Resources