i got one model that has some properties and a 1:1 relation to my second model in the same extension and i wanted to map that second model completely to tt_content.
so the user can insert a tt_content object into my first model.
No Problem in the BE. I can insert objects from the first model and in there i can insert a tt_content object. In the Database my first model got that "content" column where the uid of the tt_content object so i thought everything is correct...
But then to the Controller... i just get nothing... just a NULL value on the "content" property...
this is how i tested the "content" property:
$contentBoxes = $this->contentBoxRepository->findAll();
print(gettype($contentBoxes->current()->getContent()));
and it returns just "NULL"
aaaaaand here are some infos about that first model whitch contains the tt_content object:
First Model:
class Tx_PlusbSlidingcontent_Domain_Model_ContentBox extends Tx_Extbase_DomainObject_AbstractEntity {
/**
* Content
*
* #var Tx_PlusbSlidingcontent_Domain_Model_Content
*/
protected $content;
...........
/**
* Returns the content
*
* #return Tx_PlusbSlidingcontent_Domain_Model_Content $content
*/
public function getContent() {
return $this->content;
}
/**
* Sets the content
*
* #param Tx_PlusbSlidingcontent_Domain_Model_Content $content
* #return void
*/
public function setContent(Tx_PlusbSlidingcontent_Domain_Model_Content $content) {
$this->content = $content;
}
...............
}
Second Model:
class Tx_PlusbSlidingcontent_Domain_Model_Content extends Tx_Extbase_DomainObject_AbstractEntity {
}
The "content" section in the TCA of the first Model:
'content' => array(
'exclude' => 0,
'label' => 'LLL:EXT:plusb_slidingcontent/Resources/Private/Language/locallang_db.xml:tx_plusbslidingcontent_domain_model_contentbox.content',
'config' => array(
'type' => 'inline',
'foreign_table' => 'tt_content',
'minitems' => 0,
'maxitems' => 1,
'appearance' => array(
'collapseAll' => 0,
'levelLinksPosition' => 'top',
'showSynchronizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showAllLocalizationLink' => 1
),
),
),
And in the TS Setup i added this in "persistence":
classes {
Tx_PlusbSlidingcontent_Domain_Model_Content {
mapping {
tableName = tt_content
columns {
}
}
}
}
i just don't know where the error is in that config... doesn't the repository/model/anything have to autofill the content property on the first model with an object of the second model? at least an empty one?
(Answered by the OP in a question edit. Converted to a community wiki answer. See Question with no answers, but issue solved in the comments (or extended in chat) )
The OP wrote:
okay mystery solved...
the extension_builder adds a file called "ext_typoscript_setup.txt". In that file there is the for tt_content deadly "recordType" definition... removed that and voila... everything worked
Yes its very easy to integrate tt_content field in your extension.
If you want to set second title field in your tt_content record then you have to set following script in your ext_table.php
$tempColumns = array(
'subtitle' => array(
'exclude' => 0,
'label' => 'title2',
'config' => array(
'type' => 'input'
)
)
);
Then you have to load tt_content TCA file
#This is for EXTBASE Extension
\TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA('tt_content');
OR
#This is for PI Base Extension
t3lib_div::loadTCA("tx_dam_cat");
Following field will user for PARTICULAR EXTENSION then use following script.
$TCA["tt_content"]["types"]["list"]["subtypes_excludelist"]["abc_pqr"]="layout,select_key,pages";
$TCA["tt_content"]["types"]["list"]["subtypes_addlist"]["abc_pqr"]="subtitle;;;;1-1-1";
For more information about this then visit
https://jainishsenjaliya.wordpress.com/2014/08/25/how-to-use-tt_content-fields-in-custom-plugin-of-typo3/
Related
I'm currently getting this error when trying to load an edit form for my Profile entity.
The form's view data is expected to be an instance of class AppBundle\Entity\Profile, but is a(n) array. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) array to an instance of AppBundle\Entity\Profile.
I was Wondering if anyone knows how to fit this. I'm using a Profile controller and the User and Profile have a OneToOne relationship with each other.
Here is my code for the Profile controller that loads that form
/**
* #Route("/profile/edit", name="profile_edit")
*/
public function editAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$profileRepository = $em->getRepository(Profile::class);
$user = $this->getUser();
$profile = $profileRepository->getProfileByUserId($user->getId());
$form = $this->createForm(ProfileType::class, $profile);
$form->handlerequest($request);
if( $form_.isSubmitted() && $form->isValid()) {
$firstname = $form->get('firstname')->getData();
$lastname = $form->get('lastname')->getData();
$description = $form->get('description')->getData();
$profile->setFirstname($firstname);
$profile->setLastName($lastname);
$profile->setDescription($description);
$em->persist($profile);
$em->flush();
$this->addFlash('flash-profileeditted', 'You\'ve successfully updated your profile.');
$this->redirectToRoute('profile_page');
}
return $this->render('profile/edit.html.twig', ['form' => createForm(), 'profile' => $profile]);
}
And here is my ProfileType::class
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstname', TextType::class, [ 'label' => 'Firstname', 'attr' => ['class' => 'form-control']])
->add('lastname', TextType::class, ['label' => 'Lastname', 'attr' => ['class' => 'form-control']])
->add('description', TextareaType::class, ['label' => 'In Your Own Words', 'attr' => ['class' => 'form-control']])
->add('user')
->add('submit', SubmitType::class, ['label' => 'Edit Profile', 'attr' => ['class' => 'btn btn-info']]);
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Profile'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_profile';
}
Not Sure what else to include here, hopefully everything is ok and the solution can be found within this code.
I should also point out that I am using FOSUserBundle.
Thanks in advance,
Ok. I finally found out what was happening. I was using the Profile Repository to find a user by their id, but that was returning an array. So what I had to do is use this code:
$profile = $profileRepository->findOneByUser($user->getId());
This actually returns the Object as an AppBundle\Entity\Profile object which can then be used to populate the form.
With Symfony 3.1 and KNP menu bundle I build a 2 level menu tree.
The selected page gets highlighted within the menu.
As I am using a drop-down menu, I additionaly want the top level of menu being highlighted - basically the parent entry of my selected child.
No idea how to achieve this. Docs did not help so far. Any help appreciated.
Thanks Wolfram
It is very late and I think you have already found the way, but in case someone is still looking for it, I am giving my answer.
Basically you can achieve this via the setCurrent() method. For example, I wanted to check it with my current routes. So, what I did was,
Added request_stack in my builder service. So my service was looking something like
app.menu_builder:
class: MyBundle\Menu\MenuBuilder
arguments: ["#knp_menu.factory", "#security.authorization_checker", '#request_stack']
tags:
- { name: knp_menu.menu_builder, method: createSideMenu, alias: side }
Now the constructor part in my MenuBuilder Class was looking something like
use Knp\Menu\FactoryInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class MenuBuilder
{
/**
* #var FactoryInterface
*/
private $factory;
/**
* #var TranslatorInterface
*/
private $translator;
/**
* #var RequestStack
*/
private $requestStack;
/**
* MenuBuilder constructor.
* #param FactoryInterface $factory
* #param TranslatorInterface $translator
*/
public function __construct(
FactoryInterface $factory,
TranslatorInterface $translator,
RequestStack $requestStack
) {
$this->factory = $factory;
$this->translator = $translator;
$this->requestStack = $requestStack;
$this->prefix = $requestStack->getCurrentRequest()->get('_prefix');
}
}
Then I created my menu for example:
$menu->addChild('level1_1', array(
'label' => "<span>Committee</span>",
'uri' => '#',
'extras' => array('safe_label' => true)
));
$menu['level1_1']->addChild('level2_1', array(
'label' => "<span>Level 2 Number 1</span>",
'route' => 'route_1',
'extras' => array('safe_label' => true)
));
$menu['level1_1']->addChild('level2_2', array(
'label' => "<span>Level 2 Number 2</span>",
'route' => 'route_2',
'extras' => array('safe_label' => true)
));
$menu->addChild('level1_2', array(
'label' => "<span>Committee</span>",
'uri' => '#',
'extras' => array('safe_label' => true)
));
$menu['level1_2']->addChild('level2_3', array(
'label' => "<span>Level 2 Number 3</span>",
'route' => 'route_3',
'extras' => array('safe_label' => true)
));
$menu['level1_2']->addChild('level2_4', array(
'label' => "<span>Level 2 Number 4</span>",
'route' => 'route_4',
'extras' => array('safe_label' => true)
));
Now comes the main part. After the menu object was ready for me, I mapped the routes with it's parent and set the parent active before returning the menu object.
$request = $this->requestStack->getCurrentRequest();
$routeName = $request->get('_route');
switch ($routeName)
{
case 'route_1':
case 'route_2':
$menu['level1_1']->setCurrent(true);
break;
case 'route_3':
case 'route_4':
$menu['level1_2']->setCurrent(true);
break;
}
In place of this switch section, you can use your own login according to your needs. Hope this is clear enough to understand.
Is it possible to do while validate a form with an input filter to not just send an error message but also set the border colour change to red?
something like this:
$this->add(array(
'name' => 'test',
'required' => true,
'attributes' => array(
'style' => 'border-color:red'
),
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
\Zend\Validator\NotEmpty::IS_EMPTY => 'Please fill me out'
)
)
)
)
));
One way of doing this would be to create your own view helper to render a form element and in that add error classes if the field has errors.
To start you need to create your view helper and if the form element has errors, then you add a class.
The view helper:
namespace Application\View\Helper;
use Zend\Form\View\Helper\FormInput as ZendFormInput;
use Zend\Form\ElementInterface;
use Zend\Form\Exception;
class FormInput extends ZendFormInput
{
/**
* Render a form <input> element from the provided $element
*
* #param ElementInterface $element
* #throws Exception\DomainException
* #return string
*/
public function render(ElementInterface $element)
{
$name = $element->getName();
if ($name === null || $name === '') {
throw new Exception\DomainException(sprintf(
'%s requires that the element has an assigned name; none discovered',
__METHOD__
));
}
$attributes = $element->getAttributes();
$attributes['name'] = $name;
$attributes['type'] = $this->getType($element);
$attributes['value'] = $element->getValue();
return sprintf(
'<input %s class="form-control '.(count($element->getMessages()) > 0 ? 'error-class' : '').'" %s',
$this->createAttributesString($attributes),
$this->getInlineClosingBracket()
);
}
}
And to your module.config.php you will need to add
'view_helpers' => array(
'invokables'=> array(
'formInput' => 'Application\View\Helper\FormInput',
),
),
What I am actually doing is, fetching a list of companies from the database and passing that to the form SELECT element.
So I created a Model file, which returns an array
//=== return an array of $ID => $name of companies to use in dropdown in reports form
public function getTotalResult($table, $type, $id) {
$this->table = $table;
$select = new Select();
$spec = new Where();
$spec->equalTo('status', 1);
if ($type == 'name') {
$spec->equalTo('id', $id);
}
$select->from($this->table);
$select->where($spec);
$resultSet = $this->selectWith($select);
//$resultSet->buffer();
return $resultSet;
}
public function resultList($table){
$results = $this->getTotalResult($table, '', '');
foreach ($results as $result) {
$this->id[] = $result->id;
$this->name[] = $result->name;
}
$result = array_combine($this->id, $this->name);
return $result;
}
Then I tested this in my Controller, which returned exactly what I wanted:
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use SpangelLogin\Model\Register; // <-- Add this import
use SpangelLogin\Model\companyList; // <-- Add this import
class RegisterController extends AbstractActionController
{
protected $registerTable;
protected $companyList;
public function getcompanyList()
{
if (!$this->companyList) {
$sm = $this->getServiceLocator();
$this->companyList = $sm->get('SpangelLogin\Model\companyList');
}
return $this->companyList;
}
public function indexAction()
{
//== get list of companies
$company_table = 'rs_company';
$sector_table = 'rs_sector';
$companiesList = $this->getcompanyList()->getName($company_table, 2);
}
}
So now I want this companiesList array passed in my form's Select Element. How can I achieve that. Here is my form in which I am using select.
use Zend\Form\Form;
use Zend\Form\Element;
class SectorReportForm extends Form
{
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('sectorreport');
$companiesArray = $this->companiesList();
$sectorsArray = $this->sectorsList();
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/form-data');
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'company',
'attributes' => array(
'id' => 'company',
'multiple' => true,
'options' => $companiesArray,
),
'options' => array(
'label' => 'Company',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Upload',
'id' => 'submitbutton',
'class' => 'button violet right'
),
));
}
}
From a Design-Perspective, the best approach would be to handle this via Dependency-Injection. That sneaky little buzzword that confuses people so much, but actually is nothing more but to forward data between objects :P
General Dependency-Injection for Forms can be seen looking at the following answer, as well as my Blog article
How to get data from different model for select?
Zend\Form\Element\Select and Database-Values
If you do not want to go this approach, you can handle this at the Controller level, too.
$form = new My\Form();
$select = $form->get('selectCountries');
$model = new My\Countries();
$listData = $model->getCountriesAsArray();
$select->setValueOptions($listData);
I still advise you to go the different approach ;) Keeps the controllers more clean, too, which is always a good thing. Separation of concern!
Here’s my widget in the Form.Class:
$this->widgetSchema['schools'] = new sfWidgetFormChoice(array(
'choices' => Doctrine_Core::getTable('school')->getUsersSchools($userId),
'renderer_class' => 'sfWidgetFormSelectDoubleList',
'renderer_options' => array(
'label_unassociated' => 'Unassociated',
'label_associated' => 'Associated'
)));
The above works just fine, but the values that are stored are unassociated to the choices list referenced above. I need to store the ids of the array retrieved as the values. Instead, the list that is retrieved is chronological and the ids are ignored.
Here's the schoolTable query:
public function getUsersSchools($id){
$q =Doctrine_Query::create()
->select('id')
->from('school')
->where('user_id = ?', $id)
->execute();
return $q;
}
If I understand your question correctly you would like to store associated school ids.
Use the sfWidgetFormDoctrineChoice widget instead and it will work out of the box, as it using primary keys as ids.
$query = Doctrine_Core::getTable('school')->queryForSelect($userId);
$this->setWidget('schools', new sfWidgetFormDoctrineChoice(array(
'model' => 'school',
'query' => $query,
'multiple' => true,
'renderer_class' => 'sfWidgetFormSelectDoubleList',
'renderer_options' => array(
'label_unassociated' => 'Unassociated',
'label_associated' => 'Associated'
),
)));
$this->setValidator('schools', new sfValidatorDoctrineChoice(array(
'model' => 'schoool',
'query' => $query,
'multiple' => true,
)));
// in SchoolTable class
public function queryForSelect($userId)
{
return $this->createQuery('s')
->andWhere('s.user_id = ?', $userId)
;
}
If you has a proper schema (I presume the schools should be a many-to-many association), then the current from should has a schools_list field (properly defined in the generated base from) and then you can modify that field to be rendered by sfWidgetFormSelectDoubleList:
$this->widgetSchema['schools_list']->setOption('renderer_class', 'sfWidgetFormSelectDoubleList');
$this->widgetSchema['schools_list']->setOption('renderer_options', array(
'label_unassociated' => 'Unassociated',
'label_associated' => 'Associated'
));