From 1175fe2459ff2b5fb6b6ddda07d213ad99c53bb4 Mon Sep 17 00:00:00 2001 From: jmontoyaa Date: Thu, 4 Jan 2018 15:13:28 +0100 Subject: [PATCH] Add files from experimental --- .../ChamiloCoreExtension.php | 1 - .../BuildAttributeFormChoicesListener.php | 124 +++++++++++++ .../BuildAttributeValueFormListener.php | 104 +++++++++++ .../BuildAttributeFormSubscriber.php | 71 +++++++ .../BuildAttributeValueFormSubscriber.php | 97 ++++++++++ src/UserBundle/Form/ProfileFosUserType.php | 62 +++++++ src/UserBundle/Form/ProfileType.php | 173 ++++++++++++++++++ src/UserBundle/Form/Type/AttributeType.php | 64 +++++++ .../Form/Type/AttributeTypeChoiceType.php | 58 ++++++ .../Form/Type/AttributeValueType.php | 136 ++++++++++++++ .../Form/Type/RegistrationFormType.php | 137 ++++++++++++++ src/UserBundle/Form/UserType.php | 106 +++++++++++ 12 files changed, 1132 insertions(+), 1 deletion(-) create mode 100644 src/UserBundle/Form/EventListener/BuildAttributeFormChoicesListener.php create mode 100644 src/UserBundle/Form/EventListener/BuildAttributeValueFormListener.php create mode 100644 src/UserBundle/Form/EventSubscriber/BuildAttributeFormSubscriber.php create mode 100644 src/UserBundle/Form/EventSubscriber/BuildAttributeValueFormSubscriber.php create mode 100644 src/UserBundle/Form/ProfileFosUserType.php create mode 100644 src/UserBundle/Form/ProfileType.php create mode 100644 src/UserBundle/Form/Type/AttributeType.php create mode 100644 src/UserBundle/Form/Type/AttributeTypeChoiceType.php create mode 100644 src/UserBundle/Form/Type/AttributeValueType.php create mode 100644 src/UserBundle/Form/Type/RegistrationFormType.php create mode 100644 src/UserBundle/Form/UserType.php diff --git a/src/CoreBundle/DependencyInjection/ChamiloCoreExtension.php b/src/CoreBundle/DependencyInjection/ChamiloCoreExtension.php index 3ba09ec0d2..8d431ed09c 100644 --- a/src/CoreBundle/DependencyInjection/ChamiloCoreExtension.php +++ b/src/CoreBundle/DependencyInjection/ChamiloCoreExtension.php @@ -36,5 +36,4 @@ class ChamiloCoreExtension extends Extension { return 'chamilo_core'; } - } diff --git a/src/UserBundle/Form/EventListener/BuildAttributeFormChoicesListener.php b/src/UserBundle/Form/EventListener/BuildAttributeFormChoicesListener.php new file mode 100644 index 0000000000..37f4654afe --- /dev/null +++ b/src/UserBundle/Form/EventListener/BuildAttributeFormChoicesListener.php @@ -0,0 +1,124 @@ + + * @author Liverbool + */ +class BuildAttributeFormChoicesListener extends BaseBuildAttributeFormChoicesListener +{ + /** + * Form factory. + * + * @var FormFactoryInterface + */ + private $factory; + + /** + * Constructor. + * + * @param FormFactoryInterface $factory + */ + public function __construct(FormFactoryInterface $factory) + { + $this->factory = $factory; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + FormEvents::PRE_SET_DATA => 'buildChoices', + FormEvents::PRE_SUBMIT => 'buildConfiguration', + ); + } + + /** + * Build configuration field for attribute form. + * + * @param FormEvent $event + */ + public function buildConfiguration(FormEvent $event) + { + $data = $event->getData(); + $choices = array(); + + if (AttributeTypes::CHOICE === $data['type'] && !empty($data['choices'])) { + $choices = $data['choices']; + } + + $data['configuration'] = $choices; + + if (!$event->getForm()->has('configuration')) { + $event->getForm()->add( + $this->factory->createNamed( + 'configuration', + 'collection', + null, + array( + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + 'auto_initialize' => false, + ) + ) + ); + } + + $event->setData($data); + } + + /** + * Builds choices for attribute form. + * + * @param FormEvent $event + */ + public function buildChoices(FormEvent $event) + { + $attribute = $event->getData(); + if (null === $attribute) { + return; + } + + $type = $attribute->getType(); + + if (null === $type || AttributeTypes::CHOICE === $type) { + $data = null; + $config = $attribute->getConfiguration(); + + if (!empty($config['choices'])) { + $data = $config['choices']; + } + + $event->getForm()->add( + $this->factory->createNamed( + 'choices', + 'collection', + null, + array( + 'type' => 'text', + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + 'auto_initialize' => false, + 'mapped' => false, + 'data' => $data, + ) + ) + ); + } + } +} diff --git a/src/UserBundle/Form/EventListener/BuildAttributeValueFormListener.php b/src/UserBundle/Form/EventListener/BuildAttributeValueFormListener.php new file mode 100644 index 0000000000..03096e29aa --- /dev/null +++ b/src/UserBundle/Form/EventListener/BuildAttributeValueFormListener.php @@ -0,0 +1,104 @@ + 'onPreSetData', + FormEvents::PRE_SUBMIT => 'onPreSubmit', + ); + } + + /** + * Builds proper product form after setting the product. + * + * @param FormEvent $event + */ + public function buildForm(FormEvent $event) + { + /** @var \Chamilo\CoreBundle\Entity\ExtraFieldValues $attributeValue */ + $attributeValue = $event->getData(); + + $form = $event->getForm(); + + if (null === $attributeValue) { + $form->add( + $this->factory->createNamed( + 'value', + 'text', + null, + array('auto_initialize' => false) + ) + ); + return; + } + + $type = $attributeValue->getType(); + $attributeValue->setAttribute($attributeValue->getField()); + + $options = array( + 'label' => $attributeValue->getName(), + 'auto_initialize' => false, + ); + + if (is_array($attributeValue->getConfiguration())) { + $options = array_merge( + $options, + $attributeValue->getConfiguration() + ); + } + + $this->verifyValue($attributeValue); + + // If we're editing the attribute value, let's just render the value field, not full selection. + $form + ->remove('extraField') + ->add($this->factory->createNamed('value', $type, null, $options)); + } + + /** + * Verify value before set to form + * + * @param AttributeValueInterface $attributeValue + */ + protected function verifyValue(AttributeValueInterface $attributeValue) + { + switch ($attributeValue->getType()) { + case AttributeTypes::CHECKBOX: + if (!is_bool($attributeValue->getValue())) { + $attributeValue->setValue(false); + } + + break; + + case AttributeTypes::CHOICE: + if (!is_array($attributeValue->getValue())) { + $attributeValue->setValue(null); + } + + break; + + case AttributeTypes::MONEY: + case AttributeTypes::NUMBER: + case AttributeTypes::PERCENTAGE: + if (!is_numeric($attributeValue->getValue())) { + $attributeValue->setValue(null); + } + + break; + } + } +} diff --git a/src/UserBundle/Form/EventSubscriber/BuildAttributeFormSubscriber.php b/src/UserBundle/Form/EventSubscriber/BuildAttributeFormSubscriber.php new file mode 100644 index 0000000000..484aacd22c --- /dev/null +++ b/src/UserBundle/Form/EventSubscriber/BuildAttributeFormSubscriber.php @@ -0,0 +1,71 @@ + + */ +class BuildAttributeFormSubscriber implements EventSubscriberInterface +{ + /** + * @var FormFactoryInterface + */ + protected $factory; + + /** + * @param FormFactoryInterface $formFactory + */ + public function __construct(FormFactoryInterface $formFactory) + { + $this->factory = $formFactory; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + FormEvents::PRE_SET_DATA => 'addConfigurationFields', + ); + } + + /** + * @param FormEvent $event + */ + public function addConfigurationFields(FormEvent $event) + { + $attribute = $event->getData(); + $form = $event->getForm(); + + try { + $requiredFields = $this->factory->createNamed( + 'configuration', + 'sylius_attribute_type_configuration_'.$attribute->getType(), + null, + array( + 'auto_initialize' => false, + 'label' => 'sylius.attribute_type.configuration', + ) + ); + + $form->add($requiredFields); + } catch (InvalidArgumentException $exception) { + } + } +} diff --git a/src/UserBundle/Form/EventSubscriber/BuildAttributeValueFormSubscriber.php b/src/UserBundle/Form/EventSubscriber/BuildAttributeValueFormSubscriber.php new file mode 100644 index 0000000000..6d553a37aa --- /dev/null +++ b/src/UserBundle/Form/EventSubscriber/BuildAttributeValueFormSubscriber.php @@ -0,0 +1,97 @@ + + */ +class BuildAttributeValueFormSubscriber implements EventSubscriberInterface +{ + /** + * @var RepositoryInterface + */ + protected $attributeRepository; + + /** + * @param RepositoryInterface $attributeRepository + */ + public function __construct(RepositoryInterface $attributeRepository) + { + $this->attributeRepository = $attributeRepository; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + FormEvents::PRE_SET_DATA => 'preSetData', + FormEvents::PRE_SUBMIT => 'preSubmit', + ); + } + + /** + * @param FormEvent $event + */ + public function preSetData(FormEvent $event) + { + $attributeValue = $event->getData(); + + if (null === $attributeValue || null === $attributeValue->getAttribute()) { + return; + } + $this->addValueField($event->getForm(), $attributeValue->getAttribute()); + } + + /** + * @param FormEvent $event + */ + public function preSubmit(FormEvent $event) + { + $attributeValue = $event->getData(); + + if (!isset($attributeValue['value']) || !isset($attributeValue['attribute'])) { + throw new \InvalidArgumentException('Cannot create an attribute value form on pre submit event without "attribute" and "value" keys in data.'); + } + $form = $event->getForm(); + + $attribute = $this->attributeRepository->find($attributeValue['attribute']); + + $attribute = $attribute->getAttribute(); + + $this->addValueField($form, $attribute); + + } + + /** + * @param FormInterface $form + * @param AttributeInterface $attribute + */ + private function addValueField(FormInterface $form, AttributeInterface $attribute) + { + $options = array( + 'auto_initialize' => false, + 'label' => $attribute->getName() + ); + + $form->add('attribute'); + $form->add('value', 'sylius_attribute_type_'.$attribute->getType(), $options); + } +} diff --git a/src/UserBundle/Form/ProfileFosUserType.php b/src/UserBundle/Form/ProfileFosUserType.php new file mode 100644 index 0000000000..72f15280df --- /dev/null +++ b/src/UserBundle/Form/ProfileFosUserType.php @@ -0,0 +1,62 @@ +add('username') + ->add('email', 'email') + ; + } + + /** + * {@inheritdoc} + * + * @deprecated Remove it when bumping requirements to Symfony 2.7+ + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $this->configureOptions($resolver); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + array( + 'data_class' => 'Chamilo\UserBundle\Entity\User', + ) + ); + } + + public function getName() + { + return 'chamilo_fos_user_profile'; + } +} + diff --git a/src/UserBundle/Form/ProfileType.php b/src/UserBundle/Form/ProfileType.php new file mode 100644 index 0000000000..29fdd7012b --- /dev/null +++ b/src/UserBundle/Form/ProfileType.php @@ -0,0 +1,173 @@ +add( + 'firstname', + null, + array( + 'label' => 'form.label_firstname', + 'required' => false, + ) + ) + ->add( + 'lastname', + null, + array( + 'label' => 'form.label_lastname', + 'required' => false, + ) + ) + ->add('official_code', 'text') + //->add('groups') + ->add( + 'locale', + 'locale', + array( + 'preferred_choices' => array( + 'en', + 'fr', + 'es', + 'pt', + 'nl', + ), + ) + ) + ->add( + 'dateOfBirth', + 'birthday', + array( + 'label' => 'form.label_date_of_birth', + 'required' => false, + 'widget' => 'single_text', + ) + ) + ->add( + 'website', + 'url', + array( + 'label' => 'form.label_website', + 'required' => false, + ) + ) + ->add( + 'biography', + 'textarea', + array( + 'label' => 'form.label_biography', + 'required' => false, + ) + ) + /*->add('locale', 'locale', array( + 'label' => 'form.label_locale', + 'required' => false, + ))*/ + ->add( + 'timezone', + 'timezone', + array( + 'label' => 'form.label_timezone', + 'required' => false, + //'preferred_choices' => array('Europe/Paris', 'America/Lima'), + ) + ) + ->add( + 'phone', + null, + array( + 'label' => 'form.label_phone', + 'required' => false, + ) + ) + ->add( + 'picture', + 'sonata_media_type', + array( + 'provider' => 'sonata.media.provider.image', + 'context' => 'user', + 'required' => false, + 'data_class' => 'Chamilo\MediaBundle\Entity\Media', + ) + ) + /*->add( + 'extraFieldValues', + CollectionType::class, + array( + 'required' => false, + 'allow_add' => true, + 'allow_delete' => true, + 'type' => 'chamilo_user_extra_field_value', + 'by_reference' => false, + 'prototype' => true, + 'widget_add_btn' => ['label' => 'Add'], + 'options' => array( // options for collection fields + 'widget_remove_btn' => array('label' => 'Remove'), + 'label_render' => false, + ) + ) + )*/ + //->add('save', 'submit', array('label' => 'Update') ) + ; + + // Update Author id + /*$builder->addEventListener( + FormEvents::POST_SUBMIT, + function (FormEvent $event) use ($currentUser) { + // @var User $user + $user = $event->getData(); + $extraFields = $user->getExtrafields(); + foreach ($extraFields as $extraField) { + $extraField->setAuthor($currentUser); + } + } + );*/ + } + + /** + * {@inheritdoc} + * + * @deprecated Remove it when bumping requirements to Symfony 2.7+ + */ + /*public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $this->configureOptions($resolver); + }*/ + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + array( + 'data_class' => 'Chamilo\UserBundle\Entity\User', + ) + ); + } + + public function getName() + { + return 'chamilo_sonata_user_profile'; + } +} + diff --git a/src/UserBundle/Form/Type/AttributeType.php b/src/UserBundle/Form/Type/AttributeType.php new file mode 100644 index 0000000000..da73eaf8e8 --- /dev/null +++ b/src/UserBundle/Form/Type/AttributeType.php @@ -0,0 +1,64 @@ + + * @author Leszek Prabucki + * @author Mateusz Zalewski + */ +class AttributeType extends AbstractResourceType +{ + /** + * @var string + */ + protected $subjectName; + + /** + * @param string $dataClass + * @param array $validationGroups + * @param string $subjectName + */ + public function __construct($dataClass, array $validationGroups, $subjectName) + { + parent::__construct($dataClass, $validationGroups); + + $this->subjectName = $subjectName; + } + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->addEventSubscriber(new BuildAttributeFormSubscriber($builder->getFormFactory())) + ->addEventSubscriber(new AddCodeFormSubscriber()) + /*->add('translations', 'a2lix_translationsForms', array( + 'form_type' => sprintf('sylius_%s_attribute_translation', $this->subjectName), + 'label' => 'sylius.form.attribute.translations', + ))*/ + ->add('type', 'sylius_attribute_type_choice', array( + 'label' => 'sylius.form.attribute.type', + 'disabled' => true, + )) + ; + } + + /** + * {@inheritdoc} + */ + public function getName() + { //chamilo_user_extra_field_choice + return 'chamilo_user_attribute_type'; + return sprintf('%s_extra_field', $this->subjectName); + } +} diff --git a/src/UserBundle/Form/Type/AttributeTypeChoiceType.php b/src/UserBundle/Form/Type/AttributeTypeChoiceType.php new file mode 100644 index 0000000000..f0356ef864 --- /dev/null +++ b/src/UserBundle/Form/Type/AttributeTypeChoiceType.php @@ -0,0 +1,58 @@ + + */ +class AttributeTypeChoiceType extends AbstractType +{ + /** + * @var array + */ + private $attributeTypes; + + /** + * @param array $attributeTypes + */ + public function __construct($attributeTypes) + { + $this->attributeTypes = $attributeTypes; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefaults( + array('choices' => $this->attributeTypes) + ) + ; + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'choice'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + //return sprintf('chamilo_%s_extra_field_choice', $this->subjectName); + return 'chamilo_user_attribute_choice'; + } +} diff --git a/src/UserBundle/Form/Type/AttributeValueType.php b/src/UserBundle/Form/Type/AttributeValueType.php new file mode 100644 index 0000000000..37632cddf0 --- /dev/null +++ b/src/UserBundle/Form/Type/AttributeValueType.php @@ -0,0 +1,136 @@ + + */ +class AttributeValueType extends AbstractResourceType +{ + /** + * Attributes subject name. + * + * @var string + */ + protected $subjectName; + + /** + * @var EntityRepository + */ + protected $attributeRepository; + + /** + * @param string $dataClass + * @param array $validationGroups + * @param string $subjectName + * @param EntityRepository $attributeRepository + */ + public function __construct($dataClass, array $validationGroups, $subjectName, EntityRepository $attributeRepository) + { + parent::__construct($dataClass, $validationGroups); + + $this->subjectName = $subjectName; + $this->attributeRepository = $attributeRepository; + } + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + /*->add( + 'attribute', + sprintf('chamilo_%s_attribute_choice', $this->subjectName), + ['label' => sprintf('chamilo.form.attribute.%s_attribute_value.attribute', $this->subjectName)] + )*/ + ->addEventSubscriber( + new BuildAttributeValueFormSubscriber($this->attributeRepository) + ) + ; + +// $prototypes = array(); +// $attributes = $this->getAttributes($builder); +// +// if ($attributes) { +// /** @var \Chamilo\CoreBundle\Entity\ExtraField $attribute */ +// foreach ($attributes as $attribute) { +// if (!empty($attribute)) { +// $configuration = $attribute->getConfiguration(); +// $type = $attribute->getTypeToString(); +// +// if (!is_array($configuration)) { +// $configuration = array(); +// } +// +// if (empty($type)) { +// continue; +// } +// } +// +// $prototypes[] = $builder->create( +// 'value', +// $type, +// $configuration +// )->getForm(); +// } +// } +// +// $builder->setAttribute('prototypes', $prototypes); + } + + /** + * {@inheritdoc} + */ + /*public function buildView( + FormView $view, + FormInterface $form, + array $options + ) { + $view->vars['prototypes'] = array(); + + foreach ($form->getConfig()->getAttribute('prototypes', array()) as $name => $prototype) { + $view->vars['prototypes'][$name] = $prototype->createView($view); + } + }*/ + + /** + * {@inheritdoc} + */ + public function getName() + { + //return sprintf('sylius_%s_attribute_value', $this->subjectName); + return sprintf('chamilo_%s_extra_field_value', $this->subjectName); + } + + /** + * Get attributes + * + * @param FormBuilderInterface $builder + * + * @return AttributeInterface[] + */ + private function getAttributes(FormBuilderInterface $builder) + { + /** @var \Symfony\Component\Form\FormBuilder $extraField */ + $extraField = $builder->get('extraField'); + + if ($extraField->hasOption('choice_list')) { + + return $extraField->getOption('choice_list')->getChoices(); + } + + return []; + } +} diff --git a/src/UserBundle/Form/Type/RegistrationFormType.php b/src/UserBundle/Form/Type/RegistrationFormType.php new file mode 100644 index 0000000000..dab94205fb --- /dev/null +++ b/src/UserBundle/Form/Type/RegistrationFormType.php @@ -0,0 +1,137 @@ +add( + 'username', + null, + array( + 'label' => 'form.username', + 'translation_domain' => 'FOSUserBundle', + ) + ) + ->add('firstname', 'text') + ->add('lastname', 'text') + ->add( + 'email', + 'email', + array( + 'label' => 'form.email', + 'translation_domain' => 'FOSUserBundle', + ) + ) + ->add('captcha', 'Gregwar\CaptchaBundle\Type\CaptchaType'); + ; + + //$builder + /*->add('official_code', 'text') + ->add('email', 'email') + ->add('username', 'text') + ->add('phone', 'text') + ->add('password', 'password') + ->add('groups') + ->add('timezone', 'timezone') + ->add( + 'locale', + 'locale', + array('preferred_choices' => array('en', 'fr', 'es')) + ) + ->add( + 'picture_uri', + 'sonata_media_type', + array( + 'provider' => 'sonata.media.provider.image', + 'context' => 'user_image', + 'required' => false, + ) + ) + ->add( + 'extraFields', + 'collection', + array( + 'required' => false, + 'type' => 'chamilo_user.form.type.attribute_value_type', + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + ) + ) + ->add('save', 'submit', array('label' => 'Update'))*/ + // ; + + // Update Author id + /*$builder->addEventListener( + FormEvents::POST_SUBMIT, + function (FormEvent $event) use ($currentUser) { + // @var User $user + $user = $event->getData(); + $extraFields = $user->getExtrafields(); + foreach ($extraFields as $extraField) { + $extraField->setAuthor($currentUser); + } + } + );*/ + } + + /** + * {@inheritdoc} + * + * @deprecated Remove it when bumping requirements to Symfony 2.7+ + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $this->configureOptions($resolver); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + array( + 'class' => 'Chamilo\UserBundle\Entity\User', + ) + ); + } + + /** + * @return string + */ + public function getParent() + { + return 'fos_user_registration'; + } + + /** + * @return string + */ + public function getName() + { + return 'chamilo_sonata_user_registration'; + } +} + diff --git a/src/UserBundle/Form/UserType.php b/src/UserBundle/Form/UserType.php new file mode 100644 index 0000000000..b555ffe50b --- /dev/null +++ b/src/UserBundle/Form/UserType.php @@ -0,0 +1,106 @@ +securityContext = $securityContext; + } + + /** + * @inheritdoc + **/ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $currentUser = $this->securityContext->getToken()->getUser(); + + $builder + ->add('firstname', 'text') + ->add('lastname', 'text') + ->add('official_code', 'text') + ->add('email', 'email') + ->add('username', 'text') + ->add('phone', 'text') + ->add('password', 'password') + ->add('groups') + ->add('timezone', 'timezone') + ->add( + 'locale', + 'locale', + array('preferred_choices' => array('en', 'fr', 'es')) + ) + ->add( + 'picture_uri', + 'sonata_media_type', + array( + 'provider' => 'sonata.media.provider.image', + 'context' => 'user_image', + 'required' => false, + ) + ) + /*->add( + 'extraFields', + 'collection', + array( + 'required' => false, + //'type' => 'chamilo_user.form.type.attribute_value_type', + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + ) + )*/ + ->add('save', 'submit', array('label' => 'Update')); + + // Update Author id + $builder->addEventListener( + FormEvents::POST_SUBMIT, + function (FormEvent $event) use ($currentUser) { + /** @var User $user */ + $user = $event->getData(); + $extraFields = $user->getExtrafields(); + foreach ($extraFields as $extraField) { + $extraField->setAuthor($currentUser); + } + } + ); + } + + /** + * @param OptionsResolverInterface $resolver + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults( + array( + 'data_class' => 'Chamilo\UserBundle\Entity\User', + ) + ); + } + + /** + * @return string + */ + public function getName() + { + return 'user'; + } +} +