runtime creation of functions in phpunit - phpunit

Is there any way of creating testcases runtime by giving paramters?
Functionality of the test cases is same, just name and parameters will differ.
Like here is an example
public function testGetGiftsGivenVideo() {
$fileName = 'get-gifts-given-video.json';
$filePath = $this->path . $fileName;
$this->accessToken = $this->coreAPI->GetOAuthToken($this->loginFilePath);
$this->compareResults($filePath, $this->accessToken, true);
}
public function testGetGiftsReceivedAudio() {
$fileName = 'get-gifts-received-audio.json';
$filePath = $this->path . $fileName;
$this->accessToken = $this->coreAPI->GetOAuthToken($this->loginFilePath);
$this->compareResults($filePath, $this->accessToken, true);
}
public function testGetGiftsReceivedVideo() {
$fileName = 'get-gifts-received-video.json';
$filePath = $this->path . $fileName;
$this->accessToken = $this->coreAPI->GetOAuthToken($this->loginFilePath);
$this->compareResults($filePath, $this->accessToken, true);
}
Now all these functions are doing the same thing.

I see two possible solutions here:
As suggested by axiac in the comments, you can use data providers.
A data provider is a method returning an array of parameters to call a test method multiple times with different parameters. See the PHPUnit documentation about data providers for more information
/**
* #dataProvider provideGetGifts
* #param $filename
*/
public function testGetGifts($fileName) {
$filePath = $this->path . $fileName;
$this->accessToken = $this->coreAPI->GetOAuthToken($this->loginFilePath);
$this->compareResults($filePath, $this->accessToken, true);
}
public function provideGetGifts()
{
return array(
array('get-gifts-given-video.json'),
array('get-gifts-received-audio.json'),
array('get-gifts-received-video.json'),
);
}
The second solution, if you want to have different method names, is to simply use a second method which includes some logic of the test:
protected function compareAccessTokenWithFilePath($fileName) {
$filePath = $this->path . $fileName;
$this->accessToken = $this->coreAPI->GetOAuthToken($this->loginFilePath);
$this->compareResults($filePath, $this->accessToken, true);
}
public function testGetGiftsGivenVideo() {
$this->compareAccessTokenWithFilePath('get-gifts-given-video.json');
}
public function testGetGiftsReceivedAudio() {
$this->compareAccessTokenWithFilePath('get-gifts-given-audio.json');
}
public function testGetGiftsReceivedVideo() {
$this->compareAccessTokenWithFilePath('get-gifts-received-video.json');
}
Personally, I'd prefer the first solution. Its a little bit clearer.

Related

Get route path '/blog/{slug}' of current request in Symfony

For some logging/monitoring i would like to get the current route path including placeholders.
If my route is /blog/{slug} and the request is to http://localhost/blog/foobar what i need is "/blog/{slug}"
In request listeners this value seem to not be inside the request object. I only find the resolved path which i am not interested in.
In Compiler passes I have the issue that any Router related service I try to get from the ContainerBuilder returns an exception. If i had the
What is a clean way to obtain this?
For routes with one param:
$routeWithoutParam = substr($request->getRequestUri(),0,strrpos($request->getRequestUri(),'/'));
$routeParams = $request->attributes->get('_route_params');
$routeDefinition = $routeWithoutParam.'/{' . array_key_first($paramsArray) . '}';
echo $routeDefinition;
For routes with multiple params:
$routeParams = $request->attributes->get('_route_params');
$routeWithoutParam = '';
for ($i = 0; $i < count($routeParams); $i++) {
$routeWithoutParam = $i === 0
? substr($request->getRequestUri(), 0, strrpos($request->getRequestUri(), '/'))
: substr($routeWithoutParam, 0, strrpos($routeWithoutParam, '/'))
;
}
$routeDefinition = $routeWithoutParam.'/';
foreach (array_keys($routeParams) as $key => $param) {
$routeDefinition.= '{' . $param . '}' . ($key < count($routeParams)-1 ? '/' : '');
}
echo $routeDefinition;
You can obtain the Router and RouteCollection, that holds all the routes in your app:
// src/Listener/RouteLoggerListener.php -- namespace and use ommited
class RouteLoggerListener implements EventSubscriberInterface
{
/**
* #var LoggerInterface
*/
private $logger;
/**
* #var RouterInterface
*/
private $router;
public function __construct(LoggerInterface $logger, RouterInterface $router)
{
$this->logger = $logger;
$this->router = $router;
}
public static function getSubscribedEvents()
{
// Trigger after the RouterListener
return [KernelEvents::REQUEST => ['onKernelRequest', 50]];
}
public function onKernelRequest(RequestEvent $event)
{
// This is for sf53 and up, for previous versions, use isMasterRequest()
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
if (null == $request) {
return;
}
$matchedRoute = $request->attributes->get('_route');
if (null == $matchedRoute) {
// Bail gracefully
return;
}
$routeCollection = $this->router->getRouteCollection();
$route = $routeCollection->get($matchedRoute);
$this->logger->debug('Request route: '.$route->getPath());
}
}
Note: Using RouteCollection at runtime is highly discouraged because it triggers a recompile. As indicated in this GitHub comment, the proper way to do it would be to use ConfigCache while cache warming.

Generating and downloading a CSV from Symfony2

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');

how to get the path of a file upload and save in db using symfony2

I have created a file uploads page. In my controller I want to get the uploaded path of the view and add it in the database for a particular id. For that I want the path of the file ans send it to the repository. The problem when I am using in my controller
if ($request->getMethod() == 'POST')
{
$form->bind($request);
$file = $form["file"]->getData();
/* here it is giving the path like /tmp/phpkR4kgD */
$em = $this->getDoctrine()->getManager();
$user->upload();
}
this is my entity
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
public function upload()
{
if (null === $this->file)
{
return;
}
$this->file->move($this->getUploadRootDir(), $this->file->getClientOriginalName());
$this->path = $this->file->getClientOriginalName();
$this->file = null;
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDir() . DIRECTORY_SEPARATOR . $this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDir() . DIRECTORY_SEPARATOR . $this->path;
}
protected function getUploadRootDir()
{
return __DIR__ . '/../../../../web/'. $this->getUploadDir();
}
protected function getUploadDir()
{
return 'uploads/';
}
I have created my uploads folder in web folder of symfony
while calling upload() method from it takes the temporary path to entity.
In entity it will get the orginal path $this->path = $this->file->getClientOriginalName();
so use return statement which returns the original path to controller from there you can save it in database...

Call form values in form handler

Here is my problem.
I am curently learning Symfony and I have created a form with a formType file and a formHandler.
I'd like now to use values of the form in my handler but I can't figure how to call those values, which method can I use? I've tried many method of the request class but it doesn't work.
Could you help me please?
Here is my handler. Some of my try are still in it commented, it's quiet simple, I'm just trying to do an echo.
class adminFormHandler
{
protected $form;
protected $request;
protected $em;
public function __construct(Form $form, Request $request, EntityManager $em)
{
$this->form = $form;
$this->request = $request;
$this->em = $em;
}
public function process()
{
if( $this->request->getMethod() == 'POST' )
{
$this->form->bindRequest($this->request);
//if( $this->form->isValid() )
//{
//echo $this->request->get('nom');
//$param = $this->request->request->keys();
//$param = $this->form->getData(nom);
//echo $param;
$myfield = $form->getAttribute('nom');
echo $myfield->getData();
//echo $param;//$this->form->get('nom')->getText();
//$this->onSuccess($this->form->getData());
return true;
//}
}
return false;
}
public function onSuccess1(/*Students $students*/)
{
//$this->em->persist($students);
//$this->em->flush();
echo'on success 1';
}
public function onSuccess2()
{
//$this->em->persist($students);
//$this->em->flush();
echo'on success 2';
}
}
You can use:
$data = $this->form->getData();
$myfield = $data['nom'];
or
$myfield = $this->form->get('nom')->getData();

How to use a csv file in PHPUnit test

I wrote a DataTest case following the example 4.5 of PHPUnit manual, the url is: http://www.phpunit.de/manual/3.6/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers. But I came across with an error:
The data provider specified for DataTest::testAdd is invalid.
Data set #0 is invalid.
I thought it maybe that I edit the data.csv file in a wrong way, then I used php function fputcsv() to create data.csv file, but it also didn't work, I want to know why, and how to resolve this problem. Thanks!
P. S.: the data in data.csv is:
0,0,0
0,1,1
The codes are show as follows:
DataTest.php
require 'CsvFileIterator.php';
class DataTest extends PHPUnit_Framework_TestCase
{
public function provider()
{
return new CsvFileIterator('data.csv');
}
/**
* #dataProvider provider
*/
public function testAdd($a, $b, $c)
{
$this->assertEquals($c, $a + $b);
}
}
CsvFileIterator.php
class CsvFileIterator implements Iterator
{
protected $file;
protected $key = 0;
protected $current;
public function __construct($file)
{
$this->file = fopen($file, 'r');
}
public function __destruct()
{
fclose($this->file);
}
public function rewind()
{
rewind($this->file);
$this->current = fgetcsv($this->file);
$this->key = 0;
}
public function valid()
{
return !feof($this->file);
}
public function key()
{
return $this->key;
}
public function current()
{
return $this->current;
}
public function next()
{
$this->current = fgetcsv($this->file);
$this->key++;
}
}
The data.csv file is create by function fputcsv():
$data = array(
array(0, 0, 0),
array(0, 1, 1)
);
$fp = fopen('data.csv', 'w');
foreach($data as $v)
{
fputcsv($fp, $v);
}
fclose($fp);
Example :-)
/**
* #dataProvider provider
* #group csv
*/
public function testAdd($a, $b, $c)
{
$this->assertEquals($c, $a + $b);
}
/**
* #return array
*/
public function provider()
{
$file = file_get_contents("/Volumes/htdocs/contacts.csv","r");
foreach ( explode("\n", $file, -1) as $line )
{
$data[] = explode(',', $line);
}
return $data;
}
/*
* CREATE TO CSV FILE DATAPROVIDER
* don't create this file in your test case
*/
public function saveToCsv()
{
$list = array(
array(0,0,0),
array(0,1,1)
);
$file = fopen("/Volumes/htdocs/contacts.csv","w");
foreach ($list as $line)
{
fputcsv($file,$line);
}
fclose($file);
}
#ZongshuLin Similar issue here. Possible Solutions:
Check this data.csv. Basically I had to add a row after the last line.
You can also check my approach on GitHub when specifying the data.csv location
Use DIRECTORY_SEPARATOR constant so the script may run on any OS--Windows uses backslashes while Linux slashes.
/**
* #return CsvFileIterator
*/
public function additionProvider()
{
return new CsvFileIterator(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'storage/data.csv');
}

Resources