Symfony expecting an ArrayCollection for a single-entity attribute - object

I have entity called "Post":
/**
* #ORM\Entity(repositoryClass="App\Repository\PostRepository")
*/
class Post
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $content;
/**
* #ORM\ManyToOne(targetEntity="UserSubscriptionTier", inversedBy="posts")
* #Assert\NotBlank()
*
*/
private $subscriptionTier;
... and all the various get/set functions
}
So my main point here is that the $subscriptionTier is not a collection object, but merely a single-entity attribute.
Here is what the form type class looks like:
class PostType extends AbstractType
{
/**
* #var UserProvider
*/
protected $userProvider;
public function __construct(UserProvider $userProvider)
{
$this->userProvider = $userProvider;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, [
'label' => 'File or Files',
'required' => false,
'mapped' => false,
'multiple' => true,
'attr'=>array('style'=>'display:none;')
])
->add('content', TextareaType::class, [
'required' => false
])
->add('subscriptionTier', EntityType::class, [
'class' => UserSubscriptionTier::class,
'choices' => $this->userProvider->getCurrentUser()->getSubscriptionTiers(),
'choice_label' => 'name',
'required' => false,
'multiple' => true,
'expanded' => true
])
->add('save', SubmitType::class, array(
'attr' => array('class' => 'save')
))
;
}
So the subscriptionTier is simply a single entity attribute, with a bunch of options to select from.
Here is what it looks like when I build it out in twig, from the incoming form:
<select class="custom-select" name="subscriptions" required="required">
<option disabled selected>Visibility</option>
{% for key,val in postForm.subscriptionTier.vars.choices %}
{% if val.data.tierNumber == 1 %}
<option value="{{ val.value }}" {{ postForm.subscriptionTier.vars.value == '' and key == 0 ? ' selected ' :(val.value == postForm.subscriptionTier.vars.value ? ' selected ' : '') }}>All Subscribers</option>
{% endif %}
<option value="{{ val.value }}" {{ postForm.subscriptionTier.vars.value == '' and key == 0 ? ' selected ' :(val.value == postForm.subscriptionTier.vars.value ? ' selected ' : '') }}>{{ val.label | trans }}</option>
{% endfor %}
</select>
Here is the controller code after the form is submitted:
public function createPostAction(PostRepository $postRepository, Request $request)
{
$user = $this->getUser();
$subscriptionId = $request->request->get('subscriptions');
$userSubscriptionTier = $this->subscriptionTierRepository->find($subscriptionId);
$post = new Post();
$post->setUser($user);
$post->setSubscriptionTier($userSubscriptionTier);
$form = $this->createForm(PostType::class, $post);
It is this createForm function which triggers the following error:
Unable to transform value for property path "subscriptionTier": Expected a Doctrine\Common\Collections\Collection object.
Why is Symfony expecting a collections object for a single entity attribute? Did the multi-option choice in the form trick Symfony into expecting an ArrayCollection?

Not 100% sure but isn't it because of the 'multiple' => true here:
->add('subscriptionTier', EntityType::class, [
'class' => UserSubscriptionTier::class,
'choices' => $this->userProvider->getCurrentUser()->getSubscriptionTiers(),
'choice_label' => 'name',
'required' => false,
'multiple' => true,
'expanded' => true
])
I think it creates mutli-value select, which is expected to pass a collection with multiple values.
Here's what the docs say about this field:
multiple
type: boolean default: false
If true, the user will be able to select multiple options (as opposed to choosing just one option). Depending on the value of the expanded option, this will render either a select tag or checkboxes if true and a select tag or radio buttons if false. The returned value will be an array.
Strange thing is your twig output doesn't contain a select with "multiple" on it, so I'm a bit confused, but it's worth a try.

Related

Drupal 8 - Twig template won't get variables values

I'm trying to make a twig template to get a variable from a custom block, when I do a {{ dumb() }} it shows me the variables and their values but when I call for the variable it won't show it, even when i call the variable with dumb {{ dumb(title) }} it tells me is NULL. Could anyone help me understand what is the mistake?
Block: onyx_experiencia.php
/**
* Provides a 'Test' Block.
*
* #Block(
* id = "onyx_experiencia",
* admin_label = #Translation("Servicios OnyxGroup"),
* category = #Translation("Servicios OnyxGroup"),
* )
*/
class onyx_experiencia extends BlockBase implements BlockPluginInterface {
/**
* {#inheritdoc}
*/
public function build() {
$title = 'TestTitle34';
$desc = 'Test text 24';
$test_array = array(
'#title' => $title,
'#description' => $desc
);
return $test_array;
}
block.module: onyx_experiencia.module
<?php
/**
* Implements hook_theme().
*/
function onyx_experiencia_theme($existing, $type, $theme, $path) {
return array(
'block__serviciosonyxgroup' => array(
'template' => 'block--serviciosonyxgroup',
'render element' => 'elements',
'variables' => array(
'title' => 'TitleTest',
'description' => 'DescriptionTest'
),
),
);
}
Twig File: block--serviciosonyxgroup.html.twig
{#
/**
* #file
* Profile for onyx_experiencia block.
*/
#}
<h3>Featured Events</h3>
<p>Test: {{ title }} </p>
<p>Test: {{ description }} </p>
<ol>
{% for key, value in _context %}
<li>{{ key }}</li>
{% endfor %}
</ol>
{{ dump(content) }}
Result: This is the result i get
UPDATE Different way still not working
As seen on your screenshot:
The variables live in the variable content, not in _context
Your current template code assumes they in live _context though as they aren't prefixed with anything.
{{ title }} equals <?= isset($_context['title']) ? $_context['title'] : null; ?>
So u'd need to change the template to something like
<h3>Featured Events</h3>
<p>Test: {{ content['#title'] }} </p>
<p>Test: {{ content['#description'] }} </p>

How to fill a dropdown list from an excel file

I have a dropdown list that should be filled from an excel file column
for now I am filling the list directly:
Formbuilder:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Author', ChoiceType::class, array(
'choices' => array(
'Author1' => 'Author1',
'Author2' => 'Author2',
'Author3' => 'Author3'
)))
;
}
twig
<div class="col-xs-9 col-sm-9 col-md-9 col-lg-9">
{{ form_widget(form.Author, {'attr': {'class' : 'form-control '}}) }}
</div>
is that doable from the form builder ?
You can use phpoffice/phpexcel to read your Excel files (it will be good to use service) : http://www.techchattr.com/how-to-read-excel-files-with-php
Add it to your FormBuilder definitions as params like :
$data = $options['data'];
Pass it as 'choices' of your field
Then, pass data as params of formbuilder like ($data contains infos from phpExcel) :
$form = $this->createForm(YourType::class, $entity, ['data' => $data]);

Silex: populate form with entered data after invalid submit

After the user submits a (uncomplete) form, I want the form to show the already entered data + an error message.
Using this code, the form is empty after submitting the form:
$request = $app['request'];
$form = $app['form.factory']->createBuilder('form')
->add('name', 'text', array( 'label' => 'Ihre Name:'))
->add('comment', 'text', array('constraints' => new Assert\Length(array('min' => 15))))
->getForm();
$twig_context = array('form' => $form->createView());
$form->handleRequest($request);
if ($form->isValid()) {
$data = $form->getData();
return 'valid!';
// Send form...
} else {
// display the form
return $app['twig']->render('contact.html.twig', $twig_context);
}
Twig-template:
{{ form_start(form) }}
{{ form_widget(form) }}
<div>
<input type="submit" value="Send" />
</div>
{{ form_end(form) }}
You should create the form view last, (could be right before you render your template). In your case, the view is created before the data from Request is applied.
This:
$twig_context = array('form' => $form->createView());
$form->handleRequest($request);
Should be:
$form->handleRequest($request);
And your render method should be:
return $app['twig']->render('contact.html.twig',
array(
'form' => $form->createView()
)
);

yii2 odd/even listview with load more pagination

First data loading is fine but when i click on load more my second page data going inside even div only.
I am generating list like this:
<div class="odd">
<items>item1</items>
<items>item3</items>
<items>item5</items>
<items>item7</items>
</div>
<div class="even">
<items>item2</items>
<items>item4</items>
<items>item6</items>
<items>item8</items>
</div>
With this custom ListView class:
class ListViewOdd extends ListView
{
public function renderItems()
{
$models = $this->dataProvider->getModels();
$keys = $this->dataProvider->getKeys();
$rowsOdd = $rowsEven = [];
foreach (array_values($models) as $index => $model) {
if ($index%2 == 0) {
$rowsOdd[] = $this->renderItem($model, $keys[$index], $index);
} else {
$rowsEven[] = $this->renderItem($model, $keys[$index], $index);
}
}
return '<div class="odd">'.implode($this->separator, $rowsOdd) . '</div><div class="even">'.implode($this->separator, $rowsOdd) .'</div>'; // replace <div> to Html::tag('div', ...)
}
}
echo ListViewOdd::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
]);
But load more pagination not splitting data again into odd/even listing as my first data list.
i am not passing anything from controller and action i am using model to get data provider
<?php echo ListViewOdd::widget([
'dataProvider' => Posts::getCommonListData($industry,'user','engage',0),
'itemOptions' => ['class' => 'item post-item'],
'summary' => '',
'id' => 'my-listview-id',
'itemView' => '_Posts',
'viewParams' => [
'fullView' => true,
],
'pager' => [
'class' => \app\vendor\kop\y2sp\ScrollPager::className(),
//'negativeMargin' => '200',
'triggerText' => 'Load More',
//'triggerOffset' => 3,
'noneLeftText' => '',
],
]);
getting output like this
<div class="odd">
<items>item1</items>
<items>item3</items>
<items>item5</items>
<items>item7</items>
</div>
<div class="even">
<items>item2</items>
<items>item4</items>
<items>item6</items>
<items>item8</items>
<items>item9</items>
<items>item10</items>
<items>item11</items>
<items>item12</items>
</div>
after clicking loadmore its just loading all records inside even div and load more aoption also coming under even div
Change in method renderItems:
return '<div class="odd">'.implode($this->separator, $rowsOdd) . '</div><div class="even">'.implode($this->separator, $rowsEven) .'</div>';
Mistake is ''.implode($this->separator, $rowsOdd) .''.
Div is even, but data from $rowsOdd :)

Symfony2 display associative array in twig

I am new to the Symfony2 framework and am trying to parse some XML from the lastfm API and display information to the user. this would be in the format of album title, playcount and album image for each item.
I can display all this information so far to the user but this is not really useful as I intend to add CSS styling to my page. Any suggestions would be appreciated.
This is my Controller
/**
* #Route("/lastfm/albums", name="albums")
* #Template()
*/
public function albumsAction()
{
$albumsclass = new Album();
// pull in artist albums
$albums = simplexml_load_file('http://ws.audioscrobbler.com/2.0/? method=artist.gettopalbums&artist=imagine+dragons&api_key=370f98844440c2ecc8e5f7 c6cea8a7a4');
$rank = $albums->xpath('/lfm/topalbums/album/#rank');
$album_name_array=array();
$album_playcount_array=array();
$album_url_array=array();
$album_image_array=array();
foreach ($rank as $ranks){
foreach ($ranks as $rank_id) {
$album_name = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/name');
$album_playcount = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/playcount');
$album_url = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/url');
$album_image = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/image[4]');
}
$album_name = implode($album_name);
array_push($album_name_array,$album_name);
$album_playcount = implode($album_playcount);
array_push($album_playcount_array,$album_playcount);
$album_url = implode($album_url);
array_push($album_url_array,$album_url);
$album_image = implode($album_image);
array_push($album_image_array,$album_image);
}
$container=array();
for($i=0; $i<sizeof($album_name_array); $i++) {
array_push($container,$album_name_array[$i],$album_playcount_array[$i],$album_ur l_array[$i],$album_image_array[$i]);
}
//$hello = array('album_name'=>$album_name_array,
// 'album_playcount'=>$album_playcount_array,
// 'album_url'=>$album_url_array,
// 'album_image'=>$album_image_array,);
//array_push($album_name_array,$album_playcount_array);
return $this->render('AcmelastfmBundle:Default:albums.html.twig', array(
// 'pageData' => array(
// 'artistxml' => $artistxml,
'rank' => $rank,
'ranks' => $ranks,
//'rank_id' => $rank_id,
// 'ranks' => $ranks,
'album_name' => $album_name_array,
//'album_playcount' => $album_playcount_array[$i],
'album_url' => $album_url_array,
'album_image' => $album_image_array,
'container' =>$container,
'data' => var_export($container, true),
//
// 'hello' => $hello,
// 'james' => array('album_name' => $albumsclass->getAlbumName()),
// ),
));
}
This is my view
{% extends '::lastfmbase.html.twig' %}
{% block title %}Albums{% endblock %}
{% block body %}
{% for key in container %}
{{key}} <br>
{% endfor %}<br>
{% endblock %}
I am basically trying to convert this code in PHP to symfony2. However I cannot find a way to pass the associative array values to twig as I get an array to string conversion error
<?php
// pull in artist albums
$albums = simplexml_load_file('http://ws.audioscrobbler.com/2.0/? method=artist.gettopalbums&artist=imagine+dragons&api_key=370f98844440c2ecc8e5f7 c6cea8a7a4');
$rank = $albums->xpath('/lfm/topalbums/album/#rank');
foreach ($rank as $ranks){
foreach ($ranks as $rank_id) {
$album_name = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/name');
$album_playcount = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/playcount');
$album_url = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/url');
$album_image = $albums->xpath('/lfm/topalbums/album[#rank="'.$rank_id.'"]/image[4]');
}
$album_name = implode($album_name);
$album_playcount = implode($album_playcount);
$album_url = implode($album_url);
$album_image = implode($album_image);
print_r($rank_id);
?>
<article class="album">
<?php
echo "".$album_name."<br>";
echo $album_playcount." listeners<br>";
echo "<div><img src=\"".$album_image."\" title=\"$album_name\" /></div><br>";
?>
</article>
<?php
}
I am not sure exactly what you are asking.
Do you mean this?
{% for key, value in container %}
{{ key }}: {{ value }}
{% endfor %}

Resources