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]);
Related
I am trying to Import Excel Data in Laravel and Insert into Database. I am using maatwebsite/excel version 3 composer package and laravel version 5.8
Error screenshot:
https://imgur.com/a/2KXCE0g
Blade file: import.blade.php
<form action="{{ url('/import-excel/import') }}" method="POST" enctype="multipart/form-data">
{{ csrf_field() }}
<div class="form-group">
<label for="importFile">Select Import File</label>
<input type="file" name="select_file" class="form-controll">
</div>
<input type="submit" name="upload" class="btn btn-success" value="Import File">
</form>
Controller file: ImportExcelController.php
public function import(Request $request){
$this->validate($request, [
'select_file' => 'required|mimes:xls,xlsx'
]);
$path = $request->file('select_file')->getRealPath();
$data = Excel::import($path)->get();
if($data->count() > 0){
foreach($data->toArray() as $key => $value){
foreach($value as $row){
$insert_data[] = array(
'CustomerName' => $row['customer_name'],
'Gender' => $row['gender'],
'Address' => $row['address'],
'City' => $row['city'],
'PostalCode' => $row['postal_code'],
'Country' => $row['country'],
);
}
}
if(!empty($insert_data)){
DB::table('tbl_customer')->inset($insert_data);
}
}
return back()->with('success', 'Import data successfully!');
}
I have checked excel.php file are exits in config folder. provider and aliases added.
route
Route::get('/import-excel', 'ImportExcelController#index');
Route::post('/import-excel/import', 'ImportExcelController#import');
how to solve this please?
This is the method signature for the import method:
public function import($import, $filePath, string $disk = null, string $readerType = null);
Which means that the path is a second parameter, but you are missing the first one.
The first one should be an import class, you create one like this as an example
php artisan make:import UsersImport --model=User
Then to use it:
Excel::import(new UsersImport, $path);
You will need to let know the library how to map each row from the file into an object for your usage.
-- EDIT
So I would create a model, but you can do the same like this:
class CustomersImport implements ToCollection
{
public function collection(Collection $rows)
{
$data = [];
foreach ($rows as $row)
{
$data[] = array(
'CustomerName' => $row[0],
'Gender' => $row[1],
'Address' => $row[2],
'City' => $row[3],
'PostalCode' => $row[4],
'Country' => $row[5],
);
}
DB::table('tbl_customer')->insert($data);
}
}
So something like this, but debug what does the rows contains and make sure when you iterate you get the correct key to the correct column in your database.
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.
I have a Twig extension which returns an array, here is the code:
public function getUserSettings($user_id){
$user_preferences = array(
'background_color' => '#000000',
'text_color' => '#FFFFFF'
);
}
If I dump this array ( {{ dump(getUserSettings(app.user.id)) }} ) and I have which is fine:
array:2 [▼
"background_color" => "#000000"
"text_color" => "#FFFFFF"
]
In the Twig template I don't want to have a call to this function each time I want the background_color or the text_color.
Is there a way to assign the returning array to a twig array and then use it in the template?
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()
)
);
I have a post type called 'faq' and taxonomy called 'type' within my template and a few taxonomy terms created "Design", "Print", "Display" etc.
The idea I am trying to implement is to display only the posts that belong to assigned taxonomies (types) without duplication. Each post may be assigned to multiple taxonomies (types).
My current code works fine as long as the post have got only one taxonomy assigned to it. As soon as I assign more then one taxonomy it shows duplicate posts like this:
Question 6
Question 5
Question 1
Question 1
Here is my current code:
<?php
$post_type = 'faq';
$tax = 'type';
$faq_types = get_field('types');
$filtered = array();
$termargs = array( 'include' => $faq_types );
$tax_terms = get_terms($tax, $termargs);
if ($tax_terms) {
$i = 1;
foreach ($tax_terms as $tax_term) {
$args=array(
'post_type' => $post_type,
$tax => $tax_term->slug,
'post_status' => 'publish',
'posts_per_page' => -1,
'caller_get_posts'=> 1
);
$my_query = null;
$my_query = new WP_Query($args);
if( $my_query->have_posts() ) {
while ($my_query->have_posts()) : $my_query->the_post(); ?>
<div class="accordion-section">
<a class="accordion-section-title" href="#accordion-<?php echo $i; ?>"><i class="fa fa-chevron-right"></i> <?php the_title(); ?></a>
<div id="accordion-<?php echo $i; ?>" class="accordion-section-content">
<?php the_content(); ?>
</div>
</div>
<?php
$i++;
endwhile;
}
wp_reset_query();
}
}
?>
I'd really appreciate any help with getting this working the way I need.
Your current loop is saying "For each taxonomy term, show all posts associated with that term", so of course it will duplicate if there is one post associated with multiple terms. Take your query out of the foreach loop and use a single tax query with an array of terms:
$args = array(
'post_type' => $post_type,
'tax_query' => array(
array(
'taxonomy' => $tax,
'field' => 'slug',
'terms' => $term_slugs,
),
),
'post_status' => 'publish',
'posts_per_page' => -1,
'caller_get_posts'=> 1
);
EDIT
By the way, you'll need to convert your array of term objects to an array of term slugs for this to work properly:
$term_slugs = array();
foreach( $tax_terms as $term ) {
$terms_slugs[] = $term->slug;
}