Symfony2 controller static variable - symfony

In one of my controllers, I have some static variables and two actions:
class ChooseController extends Controller
{
private static $wholedata = array();
private static $currentdata = array();
private static $wholenum = 0;
private static $currentnum = 0;
public function choosefirstAction()
{
$company = $this->getUser()->getCompany();
$em = $this->getDoctrine()->getManager();
self::$wholedata = $this->getDoctrine()
->getRepository('NeejobCompanyBundle:Selected')->findBy(
array("company" => $company),
array("job" => 'ASC')
);
self::$wholenum = count(self::$wholedata);
self::$currentdata = array_slice(self::$wholenum, 0, 3);
self::$currentnum = 3;
return new response(json_encode(self::$currentdata));
}
public function choosemoreAction()
{
//...
return new response(self::$wholenum);
}
}
I still have $wholenum = 0, which is supposed to be 3 or larger. How should I handle the problem?

When you send the data in choosefirstAction your class values are no longer set, you need to store them somewhere (i.e. in the session) :
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\JsonResponse;
class ChooseController extends Controller
{
public function choosefirstAction()
{
$company = $this->getUser()->getCompany();
$doc = $this->getDoctrine();
$wholedata = $doc->getRepository('...Bundle:Selected')->findBy(
array('company' => $company),
array('job' => 'ASC')
);
$wholenum = count($wholedata);
$currentdata = array_slice($wholenum, 0, 3);
$currentnum = 3;
$session = $this->get('session');
$session->set('wholenum', $wholenum);
return new JsonResponse($currentdata);
}
public function choosemoreAction()
{
$wholenum = $this->get('session')->get('wholenum');
return new response($wholenum);
}
}
More on sessions in symfony here

Related

Symfony / Fixtures "Reference already exists, use method setReference in order to override it"

I created 2 fixtures files and want to link them but got the error : Reference to "genre_reference" already exists, use method setReference in order to override it.
Here is my book fixtures :
class LivreFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
$faker = Factory::create('fr_FR');
$faker->seed(123);
for ($i = 0; $i < 10; $i++) {
$livre = new Livre();
$livre->setTitre($faker->sentence($nbWords = 4, $variableNbWords = true));
$livre->setAuteur($faker->name);
$livre->setDescription($faker->text);
$livre->setDateDeParution($faker->dateTime($format = 'Y-m-d'));
$livre->setGenre($this->getReference('genre_reference'));
$manager->persist($livre);
}
$manager->flush();
}
public function getDependencies()
{
return array(
GenreFixtures::class,
);
}
}
And my genre fixtures file :
class GenreFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$faker = Factory::create('fr_FR');
$faker->seed(123);
for ($i=0; $i < 5; $i++) {
$genre = new Genre();
$genre->setName($faker->colorName);
$manager->persist($genre);
$this->addReference('genre_reference', $genre);
}
$manager->flush();
}
}
I don't really understand the setreference method, how to do it. Any help ?
I think you should add $i to your genre reference name.
$this->addReference('genre_reference_' . $i, $genre);
After that, you can use it by
$this->getReference('genre_reference_0');
//OR
$this->getReference('genre_reference_1');
//OR
$this->getReference('genre_reference_' . $i);

phpunit must be traversable or implement interface Iterator

I'm trying to unit test my service, containing a dependency Finder Component of symfony2(http://symfony.com/doc/current/components/finder.html).
I'm getting :
[Exception] Objects returned by Mock_Finder_91776c5c::getIterator()
must be traversable or implement interface Iterator
The service :
public function getFile($fileName, $path = '/')
{
if($this->wrapper == null || $this->connection == null)
throw new LogicException("call method setFTP first");
// get file on ftp server
$this->connection->open();
$downloadComplete = $this->wrapper->get($this->tmpDir . $fileName, $path . $fileName);
$this->connection->close();
if($downloadComplete == false)
return false; // TODO exception ?
// return file downloaded
$this->finder->files()->in(__DIR__);
foreach ($this->finder as $file) {
return $file;
}
return false; // TODO exception ?
}
And the test
class FtpServiceTest extends \PHPUnit_Framework_TestCase
{
protected $connectionMock;
protected $ftpWrapperMock;
protected $finderMock;
protected function setUp()
{
$this->connectionMock = $this->getConnectionMock();
$this->ftpWrapperMock = $this->getFTPWrapperMock();
$this->finderMock = $this->getFinderMock();
}
protected function tearDown()
{
}
private function getFinderMock()
{
return $this->getMockBuilder(Finder::class)
->disableOriginalConstructor()
->getMock('Iterator');
}
private function getConnectionMock()
{
return $this->getMockBuilder(Connection::class)
->disableOriginalConstructor()
->getMock();
}
private function getFTPWrapperMock()
{
return $this->getMockBuilder(FTPWrapper::class)
->disableOriginalConstructor()
->getMock();
}
// tests
public function testMe()
{
// arrange
$host = 'localhost';
$user = 'user';
$password = '1234';
$filesArray = new ArrayObject(array(''));
$service = new FtpService('var/tmp/');
$service->setFTP($this->connectionMock, $this->ftpWrapperMock);
$service->setFinder($this->finderMock);
$this->connectionMock
->expects($this->once())
->method('open');
$this->ftpWrapperMock
->expects($this->once())
->method('get')
->will($this->returnValue(true));
$this->connectionMock
->expects($this->once())
->method('close');
$this->finderMock
->expects($this->once())
->method('files')
->will($this->returnValue($this->finderMock));
$this->finderMock
->expects($this->once())
->method('in')
->will($this->returnValue($filesArray));
// act
$file = $service->getFile('/file.zip');
// assert
$this->assertInstanceOf(SplFileInfo::class, $file);
}
}
The mocked instance of the Finder class needs to implement/mock the method getIterator. The getMock method does not accept arguments so don't pass the string 'Iterator'—change the code as follows:
private function getFinderMock()
{
return $this->getMockBuilder(Finder::class)
->disableOriginalConstructor()
->getMock();
}
And add the Mocked expectation in the test method, for example:
$this->finderMock->expects($this->once())
->method('getIterator')
->willReturn(new \ArrayObject([$this->createMock(SplFileInfo::class)]));
Hope this helps.

Persisiting Many-to-Many with extra field in sonata admin

Multimedia, Gallery and GalleryMultimedia.
Both Multimedia and Gallery have a One-to-Many relationship with GalleryMultimedia which holds multimedia_id, gallery_id and position.
In my MultimediaAdmin, I added list of Galleries as below:
->with('Thematic Galleries')
->add('gallery', 'entity', array(
'class' => 'ACME\MyBundle\Entity\Gallery',
'property' => 'name',
'multiple' => true,
'expanded' => true,
'mapped' => false,))
->end()
Now I am stuck at persisiting the selected Gallery as a GalleryMultimedia object. In my Multimedia Model, I have the function below which I would love to pass the GalleryMultimedia object for persisiting but just can't figure out how.
public function setGalleries($galleries)
{
if (count($galleries) > 0) {
foreach ($galleries as $gallery)
{
$this->addGallery($gallery);
}
}
return $this;
}
Out of desparation, I added the following code in my MultimediaAdmin.php
public function prePersist($multimedia)
{
$this->preUpdate($multimedia);
}
public function preUpdate($multimedia)
{
$multimedia->setFiles($multimedia->getFiles());
$this->saveGalleries($multimedia);
}
public function saveGalleries($multimedia)
{
$galleryies = $this->getForm()->get('gallery')->getData();
$container = $this->getConfigurationPool()->getContainer();
$em = $container->get('doctrine')->getManager();
$existing_arr = array();
$existing = $em->getRepository('ACMEMyBundle:GalleryMultimedia')->findBy(array('multimedia' => $multimedia));
$gals = array();
foreach($existing as $exist)
{
$existing_arr[] = $exist->getGallery()->getId();
}
foreach($galleryies as $gallery)
{
if(in_array($gallery->getId(),$existing_arr))
{
continue;
}
else
{
$gm = new \ACME\MyBundle\Entity\GalleryMultimedia();
$gm->setGallery($gallery);
$gals[] = $gm;
$multimedia->setGalleries($gals);
}
}
}
Can someone please assist my poor soul?
I solved this by making the persisting in postPersist like this
public function postPersist($multimedia)
{
$this->postUpdate($multimedia);
}
public function postUpdate($multimedia)
{
$this->saveGalleries($multimedia);
}
Hope this will help someone out there
My way of doing it with objects:
public function preUpdate($object)
{
$this->updateCountries($object);
}
public function updateCountries(\AppBundle\Entity\Product $object){
$container = $this->getConfigurationPool()->getContainer();
$em = $container->get('doctrine')->getManager();
$form_countries = $this->getForm()->get('Country')->getData();
//form_countries is a Doctrine\Common\Collections\ArrayCollection
$object_countries = $object->getCountries();
//object_countries is a collection of \AppBundle\Entity\CountryProduct
$list = array();
foreach($object_countries as $country){
if(!$form_countries->contains($country->getCountry())){
//remove objects not in the form
$em->remove($country);
} else {
//save the others to not re add them
$list[] = $country->getCountry();
}
}
foreach($form_countries as $country){
if(!in_array($country, $list)){
//add everyone in the form but not in the list
$countryProduct = new \AppBundle\Entity\CountryProduct();
$countryProduct->setProduct($object);
$countryProduct->setCountry($country);
$countryProduct->setValuation(1);
$em->persist($countryProduct);
}
}
$em->flush();
}

How can I split router lists into modules?

I have this router list:
$router[] = $adminRouter = new RouteList('Admin');
$adminRouter[] = new Route('admin/<presenter>/<action>', 'Dashboard:default');
$router[] = $frontRouter = new RouteList('Front');
$frontRouter[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
But it would be better to separate those two router lists into module folders. In the future I will probably create more modules with different router lists. How can I separate it and after how can I register it?
Use RouteFactory
In config.neon
services:
routeFactory.Front: FrontModule\RouteFactory
routeFactory.Admin: AdminModule\RouteFactory
route:
class: \RouteFactory
setup:
- addRouteFactory(#routeFactory.Front)
- addRouteFactory(#routeFactory.Admin)
Class RouteFactory:
class RouteFactory
{
/** #var array */
private $routerFactories = array();
public function addRouteFactory(IRouteFactory $routeFactory)
{
$this->routeFactories[] = $routeFactory;
}
public function createRouter()
{
$router = new RouteList();
foreach ($this->routeFactories as $routeFactory) {
$router[] = $routeFactory->createRouter();
}
return $router;
}
}
Interface IRouteFactory:
interface IRouteFactory
{
public function createRouter();
}
Module route factories
namespace FrontModule;
class RouteFactory implements \IRouteFactory
{
public function createRouter()
{
$router = new RouteList('Front');
// your routes
return $router;
}
}

Using symfony2 routing component (outside of symfony2)

I've been searching and haven't really found much useful information. I'm looking to use the symfony2 routing component (and also yaml component) with my own personal framework but haven't found any documentation on basic setup. The documentation on the symfony site does a good job of explaining how to use the component but not much in the way of standalone setup.
Can anyone recommend a good place to start that could explain how to setup individual symfony2 components?
I ended up looking at the documentation on the symfony site, as well as the source code on github (Route.php, RouteCollection.php, RouteCompiler.php) and came up with my own basic router.
Just like symfony, I allow 4 arguments to be passed to the route class -> 1) the pattern, 2) the default controller/action, 3) regex requirements for each variable in the pattern, and 4) any options - I haven't coded for this yet as it's not in my requirements.
My main/front controller (index.php) only talks to the static Router class which has access to the other route classes in the lib\route namespace.
Router::Map basically compiles a regex string (along with default controller/action and variable names) that gets passed to the compiledRouteCollection which is used in Router::_Process to match the httpRequest against. From there, if there is a match in the process method then i set the controller/action/args based on the values of the matched compiledRoute default controller/action. If there is not a preg_match then i use the default controller/action/args from the request object. The rest is cake...
I hope someone finds this useful and it's able to save them the time I spent today working on this. Cheers!
index.php
require_once 'config/config.php';
require_once 'lib/autoload.php';
lib\Router::Map(
'users_username_id',
'users/{username}/{id}',
array('controller' => 'testController', 'action' => 'users')
);
lib\Router::Route(new lib\Request());
router.php
namespace lib;
class Router {
protected static $_controller;
protected static $_action;
protected static $_args;
protected static $_compiledRouteCollection;
private static $_instance;
private function __construct() {
self::$_compiledRouteCollection = new \lib\route\CompiledRouteCollection();
}
public static function Singleton() {
if(!isset(self::$_instance)) {
$className = __CLASS__;
self::$_instance = new $className;
}
return self::$_instance;
}
public static function Route(Request $request, $resetProperties = false) {
self::Singleton();
self::_Process($request,$resetProperties);
$className = '\\app\\controllers\\' . self::$_controller;
if(class_exists($className, true)) {
self::$_controller = new $className;
if(is_callable(array(self::$_controller, self::$_action))) {
if(!empty(self::$_args)) {
call_user_func_array(array(self::$_controller, self::$_action), self::$_args);
} else {
call_user_func(array(self::$_controller, self::$_action));
}
return;
}
}
self::Route(new \lib\Request('error'),true);
}
public static function Map($name, $pattern, array $defaults, array $requirements = array(), array $options = array()) {
self::Singleton();
$route = new \lib\route\Route($pattern,$defaults,$requirements,$options);
$compiledRoute = $route->Compile();
self::$_compiledRouteCollection->Add($name,$compiledRoute);
}
private static function _Process(Request $request, $resetProperties = false) {
$routes = array();
$routes = self::$_compiledRouteCollection->routes;
foreach($routes as $route) {
preg_match($route[0]['regex'], $request->GetRequest(), $matches);
if(count($matches)) {
array_shift($matches);
$args = array();
foreach($route[0]['variables'] as $variable) {
$args[$variable] = array_shift($matches);
}
self::$_controller = (!isset(self::$_controller) || $resetProperties) ? $route[0]['defaults']['controller'] : self::$_controller;
self::$_action = (!isset(self::$_action) || $resetProperties) ? $route[0]['defaults']['action'] : self::$_action;
self::$_args = (!isset(self::$_args) || $resetProperties) ? $args : self::$_args;
return;
}
}
self::$_controller = (!isset(self::$_controller) || $resetProperties) ? $request->GetController() : self::$_controller;
self::$_action = (!isset(self::$_action) || $resetProperties) ? $request->GetAction() : self::$_action;
self::$_args = (!isset(self::$_args) || $resetProperties) ? $request->GetArgs() : self::$_args;
}
}
request.php
namespace lib;
class Request {
protected $_controller;
protected $_action;
protected $_args;
protected $_request;
public function __construct($urlPath = null) {
$this->_request = $urlPath !== null ? $urlPath : $_SERVER['REQUEST_URI'];
$parts = explode('/', $urlPath !== null ? $urlPath : $_SERVER['REQUEST_URI']);
$parts = array_filter($parts);
$this->_controller = (($c = array_shift($parts)) ? $c : 'index').'Controller';
$this->_action = ($c = array_shift($parts)) ? $c : 'index';
$this->_args = (isset($parts[0])) ? $parts : array();
}
public function GetRequest() {
return $this->_request;
}
public function GetController() {
return $this->_controller;
}
public function GetAction() {
return $this->_action;
}
public function GetArgs() {
return $this->_args;
}
}
route.php
namespace lib\route;
class Route {
private $_pattern;
private $_defaults;
private $_requirements;
public $_options;
public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array()) {
$this->SetPattern($pattern);
$this->SetDefaults($defaults);
$this->SetRequirements($requirements);
$this->SetOptions($options);
}
public function SetPattern($pattern) {
$this->_pattern = trim($pattern);
if($this->_pattern[0] !== '/' || empty($this->_pattern)) {
$this->_pattern = '/'.$this->_pattern;
}
}
public function GetPattern() {
return $this->_pattern;
}
public function SetDefaults(array $defaults) {
$this->_defaults = $defaults;
}
public function GetDefaults() {
return $this->_defaults;
}
public function SetRequirements(array $requirements) {
$this->_requirements = array();
foreach($requirements as $key => $value) {
$this->_requirements[$key] = $this->_SanitizeRequirement($key,$value);
}
}
public function GetRequirements() {
return $this->_requirements;
}
public function SetOptions(array $options) {
$this->_options = array_merge(
array('compiler_class' => 'lib\\route\\RouteCompiler'),
$options
);
}
public function GetOptions() {
return $this->_options;
}
public function GetOption($name) {
return isset($this->_options[$name]) ? $this->_options[$name] : null;
}
private function _SanitizeRequirement($key, $regex) {
if($regex[0] == '^') {
$regex = substr($regex, 1);
}
if(substr($regex, -1) == '$') {
$regex = substr($regex,0,-1);
}
return $regex;
}
public function Compile() {
$className = $this->GetOption('compiler_class');
$routeCompiler = new $className;
$compiledRoute = array();
$compiledRoute = $routeCompiler->Compile($this);
return $compiledRoute;
}
}
routeCompiler.php
namespace lib\route;
class RouteCompiler {
//'#\/tellme\/users\/[\w\d_]+\/[\w\d_]+#'
public function Compile(Route $route) {
$pattern = $route->GetPattern();
$requirements = $route->GetRequirements();
$options = $route->GetOptions();
$defaults = $route->GetDefaults();
$len = strlen($pattern);
$tokens = array();
$variables = array();
$pos = 0;
$regex = '#';
preg_match_all('#.\{([\w\d_]+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
if(count($matches)) {
foreach($matches as $match) {
if($text = substr($pattern, $pos, $match[0][1] - $pos)) {
$regex .= str_replace('/', '\/', $text).'\/';
}
if($var = $match[1][0]) {
if(isset($requirements[$var])) {
$regex .= '('.$requirements[$var].')\/';
} else {
$regex .= '([\w\d_]+)\/';
}
$variables[] = $match[1][0];
}
$pos = $match[0][1] + strlen($match[0][0]);
}
$regex = rtrim($regex,'\/').'#';
} else {
$regex .= str_replace('/', '\/', $pattern).'#';
}
$tokens[] = array(
'regex' => $regex,
'variables' => $variables,
'defaults' => $defaults
);
return $tokens;
}
}
compiledRouteCollection.php
namespace lib\route;
class CompiledRouteCollection {
public $routes;
public function __construct() {
$this->routes = array();
}
public function Add($name, array $route) {
$this->routes[$name] = $route;
}
}

Resources