Generating and downloading a CSV from Symfony2 - symfony

I'm trying to create a function in my Symfony project that runs a query on the database based on a search term, retrieves the data then generates a CSV and downloads it. I've followed some guides on how to do this and although the function does not fail, it also does not seem to work.
Here is the function that runs the generate csv:
public function exportCSVAction($filter)
{
$container = $this->container;
$response = new StreamedResponse(function() use($container,$filter) {
$em = $container->get('doctrine')->getManager();
$project_repo = $em->getRepository('AppBundle:Project');
$results = $project_repo->getSearchResults($filter,true);
$handle = fopen('php://output', 'w+');
while (false !== ($row = $results)) {
fputcsv($handle, $row[0]);
$em->detach($row[0]);
}
fclose($handle);
});
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition','attachment; filename="'.getcwd().'/csv/jobs-export.csv"');
return $response;
}
The getSearchResults function in my Repository:
public function getSearchResults($filter,$array=false)
{
$qb = $this->createQueryBuilder('p')
->select('p')
->leftJoin('AppBundle:Oc73Customer', 'c', 'WITH', 'c.customerId = p.customerId')
->leftJoin('AppBundle:Oc73Product', 'pr', 'WITH', 'pr.productId = p.productId')
->where('c.firstname LIKE :filter')
->orWhere('c.lastname LIKE :filter')
->orWhere('pr.model LIKE :filter')
->orWhere('p.pONumber LIKE :filter')
->setParameter('filter', '%'.$filter.'%');
if($array == true) {
return $qb->getQuery()->getArrayResult();
} else {
return $qb->getQuery()->getResult();
}
}
As you can see, if $array is passed as true, it returns an Array result required for the CSV.
I run the exportCSVAction function if a specific query string is passed:
if($request->get('export')) {
$this->exportCSVAction($request->get('s'));
}
The page it is run on is a list of projects, and is filtered if the 's' query is passed. If 'export' is also passed it runs the exportCSVAction as above.
The function throws no errors, but it just does not download the file - I'm not sure how to debug it since the code is wrapped in a $response object, so it doesn't actually run until it gets returned.
If anyone can shed any light on this I would be grateful.

i used Symfony\Component\HttpFoundation\Response;
here is my ex:
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Customers;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ReportController extends Controller
{
/**
* #Route("/report/export_customers_data.csv", name="export_customers_data_csv")
*/
public function exportCustomersDataCsvAction()
{
$customers = $this->getCustomersFromDatabase();
$rows = array();
foreach ($customers as $event) {
$data = array(
$event->getId(),
$event->getcustNameOne(),
$event->getcustNameTwo(),
$event->getcustAddress(),
$event->getcustCountry(),
$event->getcustBusiness(),
$event->getcustEmail(),
$event->getcustPhone(),
$event->getspecialReq()
);
$rows[] = implode(',', $data);
}
$content = implode("\n", $rows);
$response = new Response($content);
$response->headers->set('Content-Type', 'text/csv');
return $response;
}
public function getCustomersFromDatabase()
{
$customers = $this->getDoctrine()
->getRepository('AppBundle:Customers')
->findAll();
return $customers;
}
}
when i call "/report/export_customers_data.csv" the download is starting automaticaly

Can you try something like this?
$response->headers->set('Content-Encoding', 'UTF-8');
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
$response->headers->set('Content-Disposition', 'attachment; filename=sample.csv');
return $response;
The problem might be here: filename="'.getcwd().'/csv/jobs-export.csv"'
A string is expected, the file name...not a relative path.

You can try this:
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition','attachment; filename="sample"');
You don`t need
$response->headers->set('Content-Type', 'application/force-download');

Related

Twilio - Laravel issue - Credentials are required to create a Client

I am receiving the following error
[2018-12-18 12:12:46] local.ERROR: Credentials are required to create a Client {"exception":"[object] (Twilio\Exceptions\ConfigurationException(code: 0): Credentials are required to create a Client at C:\wamp64\www\_javid\javid\vendor\twilio\sdk\Twilio\Rest\Client.php:157)
I will include the code below and the source i used to create it. I would like to add, this was all working correctly the other evening.
Today, i merely added a new function to handle the saving of messages to the database. Then i started receiving the above error. Naturally i reverted my changes but still the same error.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Auth;
use JWTAuth;
use App\Item;
use Log;
use Twilio\Rest\Client;
class MessagingController extends Controller
{
protected $client;
public function __construct(Client $client){
$this->client = $client;
}
/**
* Show the form for creating a notification.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('notifications.create');
}
public function sendMessage(request $request){
$details = $request->only('membershipNumber', 'countryCode', 'message');
$user = User::where('membership_number', $details['membershipNumber'])->with('mobile_number')->first();
if(count($user)>0){
$this->messageSaveToDatabase($details, $user);
$this->messageSendToMobile($details, $user);
$this->messageSendToEmail($details, $user);
return response([
'status' => 'success',
'msg' => __('messages.success'),
'response' => $details
], 200);
} else {
return response([
'status' => 'error',
'msg' => __('messages.error')
], 200);
}
}
protected function messageSaveToDatabase($details, $user){
}
protected function messageSendToMobile($details, $user, $imageUrl = null){
$lineBreak = "\n\n";
$phoneNumber = $user->mobile_number->country_code.decrypt($user->mobile_number->number);
$message = "Hi member #".$details['membershipNumber'].$lineBreak.
$details['message'];
$twilioPhoneNumber = config('services.twilio')['phoneNumber'];
$messageParams = array(
'from' => $twilioPhoneNumber,
'body' => $message
);
if ($imageUrl) {
$messageParams['mediaUrl'] = $imageUrl;
}
$this->client->messages->create(
$phoneNumber,
$messageParams
);
}
protected function messageSendToEmail($details, $user){
}
}
I have checked the TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN, these are both correct.
The code was taken from the following guide, i stripped out the subscriber part. Guide from Twilio
one more thing, I found the following Here which suggests i need to do something like this $client = new Client($keySid, $keySecret, $accountSid); but the guide above, does not do this, plus it all worked like this also.
Any help or suggestions would be great, i'm running out of hair to pull out :(
After a little more googling and some re-working, I found a working solution
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Auth;
use Twilio\Rest\Client;
class MessagingController extends Controller
{
protected function messageSendToMobile($details, $message, $user, $imageUrl = null){
$accountSid = env('TWILIO_ACCOUNT_SID');
$authToken = env('TWILIO_AUTH_TOKEN');
$twilioNumber = env('TWILIO_PHONE_NUMBER');
$lineBreak = "\n\n";
$to = $user->mobile_number->country_code.decrypt($user->mobile_number->number);
$client = new Client($accountSid, $authToken);
try {
$client->messages->create(
$to,
[
"body" => $message,
"from" => $twilioNumber
]
);
Log::info('Message sent to ' . $twilioNumber);
} catch (TwilioException $e) {
Log::error(
'Could not send SMS notification.' .
' Twilio replied with: ' . $e
);
}
}
}

Symfony2.6 - Service

I have learnt Symfony2 since several months.
I have created a service. When I use it in a simple controller, I have no problem. When I use it in my controller that manages my entity, I have a problem.
My service is:
<?php
namespace Cours\BlogBundle\Services;
class Service1
{
public function creerSlug($texte)
{
$texte = transliterator_transliterate("Latin-ASCII; [:Punctuation:] Remove; Lower();", $texte);
$texte = preg_replace('/[-\s]+/', '-', $texte);
$texte = trim($texte, '-');
return $texte;
}
}
My simple controller is:
<?php
namespace Cours\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Cours\BlogBundle\Services\Service1;
class TestController extends Controller
{
public function indexAction()
{
$texte = "Le test du slug";
$service1 = $this->container->get('service1');
$texte = $service1->creerSlug($texte);
return $this->render('CoursBlogBundle:Test:index.html.twig', array('texte' => $texte));
}
}
The action of my controller that manages my entity is:
public function ajouterAction(Request $request)
{
$rubrique = new Rubrique();
$form = $this->createForm(new RubriqueType(), $rubrique);
if ($request->isMethod('POST'))
{
$form->handleRequest($request);
if ($form->isValid())
{
$manager = $this->getDoctrine()->getManager();
$rubrique = $form->getData();
$texte = $rubrique->getTexte();
$service1 = $this->container->get('service1');
$slug = $serviceSlug->creerSlug($texte);
$slug = $rubrique->setSlug($slug);
$manager->persist($rubrique);
$manager->flush();
return $this->redirect($this->generateUrl('cours_blog_accueil'));
}
}
return $this->render('CoursBlogBundle:Rubrique:ajouter.html.twig', array('form' => $form->createView()));
}
My view tells me that my slug can’t be empty.
I think there is a mistake in my action but I can’t find it.
Does anyone help me?
KISSES AND THANK YOU VERY MUCH
change
$service1 = $this->container->get('service1');
$slug = $serviceSlug->creerSlug($texte);
to
$serviceSlug = $this->container->get('service1');
$slug = $serviceSlug->creerSlug($texte);
I suggest to comment/remove $rubrique = $form->getData(); $texte = $rubrique->getTexte(); from ajouterAction and set the text manually (just for testing purpose):
if ($form->isValid())
{
$manager = $this->getDoctrine()->getManager();
// $rubrique = $form->getData();
// $texte = $rubrique->getTexte();
$rubrique->setTexte('Some text');
$service1 = $this->get('service1');
$slug = $service1->creerSlug($rubrique->getTexte());
...
if it works, you can set some validations to the texte field in your form type which prevents entering an invalid value.
Also I suggest to use some libraries (Cocur/Slugify can be a good option) instead of handling the process by yourself.

How to implement a nice solution for multilang entity slug based routes in Symfony2

I'd like to create a simple bundle to handle some multilingual pages in a website with translated slugs.
Based on translatable, sluggable and i18nrouting
implemented an entity (Page) with title, content, slug fields + locale property as the doc says
created a new Page set its title and content then translated it by $page->setTranslatableLocale('de'); and set those fields again with the german values, so that the data in the tables looks fine, they are all there
implemented the controller with type hinting signature: public function showAction(Page $page)
generated some urls in the template by: {{ path("page_show", {"slug": "test", "_locale": "en"}) }} and {{ path("page_show", {"slug": "test-de", "_locale": "de"}) }}, routes are generated fine, they look correct (/en/test and /de/test-de)
clicking on them:
Only the "en" translation works, the "de" one fails:
MyBundle\Entity\Page object not found.
How to tell Symfony or the Doctrine or whatever bundle to use the current locale when retrieving the Page? Do I have to create a ParamConverter then put a custom DQL into it the do the job manually?
Thanks!
Just found another solution which I think is much nicer and i'm going to use that one!
Implemented a repository method and use that in the controller's annotation:
#ParamConverter("page", class="MyBundle:Page", options={"repository_method" = "findTranslatedOneBy"})
public function findTranslatedOneBy(array $criteria, array $orderBy = null)
{
$page = $this->findOneBy($criteria, $orderBy);
if (!is_null($page)) {
return $page;
}
$qb = $this->getEntityManager()
->getRepository('Gedmo\Translatable\Entity\Translation')
->createQueryBuilder('t');
$i = 0;
foreach ($criteria as $name => $value) {
$qb->orWhere('t.field = :n'. $i .' AND t.content = :v'. $i);
$qb->setParameter('n'. $i, $name);
$qb->setParameter('v'. $i, $value);
$i++;
}
/** #var \Gedmo\Translatable\Entity\Translation[] $trs */
$trs = $qb->groupBy('t.locale', 't.foreignKey')->getQuery()->getResult();
return count($trs) == count($criteria) ? $this->find($trs[0]->getForeignKey()) : null;
}
It has one disadvantage there is no protection against same translated values ...
I found out a solution which i'm not sure the best, but works.
Implemented a PageParamConverter:
class PageParamConverter extends DoctrineParamConverter
{
const PAGE_CLASS = 'MyBundle:Page';
public function apply(Request $request, ParamConverter $configuration)
{
try {
return parent::apply($request, $configuration);
} catch (NotFoundHttpException $e) {
$slug = $request->get('slug');
$name = $configuration->getName();
$class = $configuration->getClass();
$em = $this->registry->getManagerForClass($class);
/** #var \Gedmo\Translatable\Entity\Translation $tr */
$tr = $em->getRepository('Gedmo\Translatable\Entity\Translation')
->findOneBy(['content' => $slug, 'field' => 'slug']);
if (is_null($tr)) {
throw new NotFoundHttpException(sprintf('%s object not found.', $class));
}
$page = $em->find($class, $tr->getForeignKey());
$request->attributes->set($name, $page);
}
return true;
}
public function supports(ParamConverter $configuration)
{
$name = $configuration->getName();
$class = $configuration->getClass();
return parent::supports($configuration) && $class == self::PAGE_CLASS;
}
}
TranslationWalker nicely gets the entity in active locale:
class PagesRepository extends \Doctrine\ORM\EntityRepository
{
public function findTranslatedBySlug(string $slug)
{
$queryBuilder = $this->createQueryBuilder("p");
$queryBuilder
->where("p.slug = :slug")
->setParameter('slug', $slug)
;
$query = $queryBuilder->getQuery();
$query->setHint(
Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
);
return $query->getSingleResult();
}
}
And in controller
/**
* #Entity("page", expr="repository.findTranslatedBySlug(slug)")
* #param $page
*
* #return Response
*/
public function slug(Pages $page)
{
// thanks to #Entity annotation (Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity)
// Pages entity is automatically retrieved by slug
return $this->render('content/index.html.twig', [
'page' => $page
]);
}

Moving replicated codes somewhere appropriate and access them from all controllers

I want to be able to access a code from all my controllers so what is the best way of doing it? The code below is to handle form errors and I've been replicating it in every single controller in my project.
So I want to keep getErrorMessages() somewhere else and access it in controller below.
Note: I read about services but got confused and this example!
Example Controller:
class HelloController extends Controller
{
public function processAction(Request $request)
{
//More code here
if ($form->isValid() !== true)
{
$errors = $this->getErrorMessages($form);
return $this->render('SayHelloBundle:hello.html.twig',
array(
'page' => 'Say Hello',
'form' => $form->createView(),
'form_errors' => $errors
));
}
//More code here
}
private function getErrorMessages(FormInterface $form)
{
$errors = array();
foreach ($form->getErrors() as $error)
{
$errors[] = $error->getMessage();
}
foreach ($form->all() as $child)
{
if (! $child->isValid())
{
$options = $child->getConfig()->getOptions();
$field = $options['label'] ? $options['label'] : $child->getName();
$errors[$field] = implode('; ', $this->getErrorMessages($child));
}
}
return $errors;
}
}
You could create a class that has all the base operations in it and call that class (or set of classes) in your controllers.
OK did it :)
/var/www/html/local/sport/app/config/config.yml
imports:
- { resource: services.yml }
/var/www/html/local/sport/app/config/services.yml
parameters:
form_errors.class: Football\TeamBundle\Services\FormErrors
services:
form_errors:
class: %form_errors.class%
/var/www/html/local/sport/src/Football/TeamBundle/Services/FormErrors.php
namespace Football\TeamBundle\Services;
use Symfony\Component\Form\FormInterface;
class FormErrors
{
public function getErrors(FormInterface $form)
{
$errors = array();
//This part get global form errors (like csrf token error)
foreach ($form->getErrors() as $error)
{
$errors[] = $error->getMessage();
}
//This part get errors for form fields
foreach ($form->all() as $child)
{
if (! $child->isValid())
{
$options = $child->getConfig()->getOptions();
$field = $options['label'] ? $options['label'] : ucwords($child->getName());
//There can be more than one field error, that's why implode is here
$errors[strtolower($field)] = implode('; ', $this->getErrors($child));
}
}
return $errors;
}
}
controller
if ($form->isValid() !== true) {
$errors = $this->get('form_errors')->getErrors($form);
echo '<pre>'; print_r($errors); exit;
}

Create my own entity generator on symfony using doctrine generator

I am building an entity generator in order to update my DB's structure and data according to a distant one (DB), via SOAP WS...
I get the structure from an array, and am currently writing my entity classes by myself, with a file_put_content().
But as I advance, I can't help noticing that the Doctrine\ORM\Tools\EntityGenerator already does what I intend to do, way better I would ever be able to!!
So i was wondering if there was a way to use this implemented generator from my controller?
I mean, this is what Symfony is all about right? Using existing classes & bundles from anywhere in my code? :)
Any idea someOne?
Thx :)
You can use this code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator;
use Sensio\Bundle\GeneratorBundle\Command\Validators;
class MyController extends Controller
{
private $generator;
public function generateEntityAction()
{
$format = "annotation"; //it can also be yml/php/xml
$fields = "title:string(255) body:text";
$withRepository = false; //true/false
$entity = Validators::validateEntityName("MyBundle:EntityName");
list($bundle, $entity) = $this->parseShortcutNotation($entity);
$format = Validators::validateFormat($format);
$fields = $this->parseFields($fields);
$bundle = $this->get('service_container')->get('kernel')->getBundle($bundle);
$generator = $this->getGenerator();
$generator->generate($bundle, $entity, $format, array_values($fields), $withRepository);
}
protected function createGenerator()
{
return new DoctrineEntityGenerator($this->get('service_container')->get('filesystem'), $this->get('service_container')->get('doctrine'));
}
protected function getSkeletonDirs(BundleInterface $bundle = null)
{
$skeletonDirs = array();
if (isset($bundle) && is_dir($dir = $bundle->getPath() . '/Resources/SensioGeneratorBundle/skeleton')) {
$skeletonDirs[] = $dir;
}
if (is_dir($dir = $this->get('service_container')->get('kernel')->getRootdir() . '/Resources/SensioGeneratorBundle/skeleton')) {
$skeletonDirs[] = $dir;
}
$skeletonDirs[] = __DIR__ . '/../Resources/skeleton';
$skeletonDirs[] = __DIR__ . '/../Resources';
return $skeletonDirs;
}
protected function getGenerator(BundleInterface $bundle = null)
{
if (null === $this->generator) {
$this->generator = $this->createGenerator();
$this->generator->setSkeletonDirs($this->getSkeletonDirs($bundle));
}
return $this->generator;
}
protected function parseShortcutNotation($shortcut)
{
$entity = str_replace('/', '\\', $shortcut);
if (false === $pos = strpos($entity, ':')) {
throw new \InvalidArgumentException(sprintf('The entity name must contain a : ("%s" given, expecting something like AcmeBlogBundle:Blog/Post)', $entity));
}
return array(substr($entity, 0, $pos), substr($entity, $pos + 1));
}
private function parseFields($input)
{
if (is_array($input)) {
return $input;
}
$fields = array();
foreach (explode(' ', $input) as $value) {
$elements = explode(':', $value);
$name = $elements[0];
if (strlen($name)) {
$type = isset($elements[1]) ? $elements[1] : 'string';
preg_match_all('/(.*)\((.*)\)/', $type, $matches);
$type = isset($matches[1][0]) ? $matches[1][0] : $type;
$length = isset($matches[2][0]) ? $matches[2][0] : null;
$fields[$name] = array('fieldName' => $name, 'type' => $type, 'length' => $length);
}
}
return $fields;
}
}
Mostly, it comes from Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineEntityCommand and Sensio\Bundle\GeneratorBundle\Command\GeneratorCommand

Resources