How to set or get value from cache in symfony2.8? - symfony

In my service.yml
cache:
class: Doctrine\Common\Cache\PhpFileCache
arguments: [%kernel.cache_dir%]
And in my controller
$cache = $this->get('cache');
if ($cache->fetch($cache_key) != NULL) {
// mycode
}
My SilencedError is
1-include(\app\cache\dev\30\446f637472696e654e616d65737061636543616368654b65795b5d.doctrinecache.php): failed to open stream: No such file or directory

you are trying to fetch an entry without checking if it exists. Use $cache->contains($cache_key) before fetching the entry.
As the PhpFileCache class extends FileCache which extends CacheProvider you should check the classes for available functions to create and retrieve cache entries:
/**
* {#inheritdoc}
*/
public function fetch($id)
{
...
}
/**
* {#inheritdoc}
*/
public function fetchMultiple(array $keys)
{
...
}
/**
* {#inheritdoc}
*/
public function saveMultiple(array $keysAndValues, $lifetime = 0)
{
...
}
/**
* {#inheritdoc}
*/
public function contains($id)
{
...
}
/**
* {#inheritdoc}
*/
public function save($id, $data, $lifeTime = 0)
{
...
}

Related

How to set controller for any route to get basic objects in all controllers

I am building my own CMS system. And i did a lot of work with symfony in the past, now i wanna do all a bit more pro :) I want to render basic controller for admin dashboard witch contains a menu, systemnotifications on route "/admin" and then i want to set another controller for example "test" on route "/admin/test" and my problem is that all object notifications from controller named AdminController are not available in this second route "/admin/test", only on route "/admin"
Here my adminControler controller:
class AdminController extends Controller
{
/**
* #Route("/admin", name="adminDashboard")
*/
public function adminDashboard()
{
$loggedUser = $this->getUser()->getId();
$systemnotifications = $this->forward('App\Controller\SystemNotificationController::notif', [
'loggedUser' => $loggedUser
]);
return $this->render('admin/index.html.twig', [
'systemnotifications' => $systemnotifications
]);
}
}
Here my test controller:
class TestController extends Controller
{
/**
* #Route("/admin/test", name="test")
*/
public function test()
{
return $this->render('admin/dashboard/index.html.twig', [
]);
}
}
In twig is set, that adminController extends base.html.twig, and Test controller extends index.html.twig (this one witch is rendered from adminController.
My question is how to handle it properly with Symfony best practice. How i should set the Admin Controller for get systemnotifications object where is another Test Controller launched ?
Please help :)
There are two ways to do that the first is inyect in the twig the variable. example see this doc.
# config/packages/twig.yaml
twig:
# ...
globals:
# the value is the service's id
user_management: '#App\DataProvider\UserDataProvider'
# config/services.yaml
services:
'App\DataProvider\UserDataProvider':
arguments:
- '#session'
autoconfigure: false
The other way is more complicate, if you for example wants the responsability to render specific part of the page, like ... the barnav or the messages
Add this piece of code to the default twig:
{% block user_control %}
{{ render(controller('LayoutCoreBundle:User:index')) }}
{% endblock %}
<?php
namespace App\Controller;
use App\Event\ShowUserEvent;
use App\Event\ThemeEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use \stdClass;
class UserController extends EmitterController
{
/**
* #return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction()
{
if (!$this->getDispatcher()->hasListeners(ThemeEvents::THEME_NAVBAR_USER)) {
return new Response();
}
/** #var ShowUserEvent $userEvent */
$userEvent = $this->triggerMethod(ThemeEvents::THEME_NAVBAR_USER, new ShowUserEvent());
$userClass = $userEvent->getUser();
$user = new stdClass();
$user->id = $userClass->getIdentifier();
$user->idEmployee = $userClass->getIdEmployee();
$user->setCompanyLogo = $userClass->getCompanyLogo();
$user->companyName = $userClass->getCompanyName();
$user->company = $userClass->getCompany();
$user->avatar = $userClass->getAvatar();
$user->fullName = $userClass->getName();
$user->menu = $userClass->getMenu();
$user->role = $userClass->getRolname();
return $this->render(
'header/index.html.twig',
[
'userJson' => $user,
]
);
}
}
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class EmitterController extends AbstractController
{
/**
* #var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* #param EventDispatcherInterface $dispatcher
*/
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->eventDispatcher = $dispatcher;
}
/**
* #return EventDispatcherInterface
*/
protected function getDispatcher()
{
return $this->eventDispatcher;
}
/**
* #param string $eventName
*
* #return bool
*/
protected function hasListener($eventName)
{
return $this->getDispatcher()->hasListeners($eventName);
}
/**
* Will look for a method of the format "on<CamelizedEventName>" and call it with the event as argument.
*
*
* Then it will dispatch the event as normal via the event dispatcher.
*
* #param $eventName
* #param Event $event
*
* #return Event
*/
protected function triggerMethod($eventName, Event $event)
{
$method = sprintf('on%s', Container::camelize(str_replace('.', '_', $eventName)));
if (is_callable([$this, $method])) {
call_user_func_array([$this, $method], [$event]);
}
if ($event->isPropagationStopped()) {
return $event;
}
$this->getDispatcher()->dispatch($eventName, $event);
return $event;
}
}
interface ThemeEvents
{
/**
* Used to receive notification data
*/
public const THEME_NOTIFICATIONS = 'theme.notifications';
/**
* Used to receive message data
*/
public const THEME_MESSAGES = 'theme.messages';
/**
* Used to receive task data
*/
public const THEME_TASKS = 'theme.tasks';
/**
* Used to receive the current user for the navbar
*/
public const THEME_NAVBAR_USER = 'theme.navbar_user';
/**
* Used to receive breadcrumb data
*/
public const THEME_BREADCRUMB = 'theme.breadcrumb';
/**
* Used to receive the current user for the sidebar
*/
public const THEME_SIDEBAR_USER = 'theme.sidebar_user';
/**
* Used to receive the sidebar menu data
*/
public const THEME_SIDEBAR_SETUP_MENU = 'theme.sidebar_setup_menu';
}
class ShowUserEvent extends ThemeEvent
{
/**
* #var UserInterface
*/
protected $user;
/**
* #var bool
*/
protected $showProfileLink = true;
/**
* #var bool
*/
protected $showLogoutLink = true;
/**
* #var NavBarUserLink[]
*/
protected $links = [];
/**
* #param UserInterface $user
* #return ShowUserEvent
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* #return UserInterface
*/
public function getUser()
{
return $this->user;
}
/**
* #return NavBarUserLink[]
*/
public function getLinks()
{
return $this->links;
}
/**
* #param NavBarUserLink $link
* #return ShowUserEvent
*/
public function addLink(NavBarUserLink $link)
{
$this->links[] = $link;
return $this;
}
/**
* #return bool
*/
public function isShowProfileLink()
{
return $this->showProfileLink;
}
/**
* #param bool $showProfileLink
* #return ShowUserEvent
*/
public function setShowProfileLink($showProfileLink)
{
$this->showProfileLink = $showProfileLink;
return $this;
}
/**
* #return bool
*/
public function isShowLogoutLink()
{
return $this->showLogoutLink;
}
/**
* #param bool $showLogoutLink
* #return ShowUserEvent
*/
public function setShowLogoutLink($showLogoutLink)
{
$this->showLogoutLink = $showLogoutLink;
return $this;
}
}
class ThemeEvent extends Event
{
}
And then only you need a evensuscriber
class NavbarUserSubscriber implements EventSubscriberInterface
{
/**
* #var Security
*/
protected $security;
/**
* #param Security $security
*/
public function __construct(Security $security)
{
$this->security = $security;
}
/**
* #return array
*/
public static function getSubscribedEvents(): array
{
return [
ThemeEvents::THEME_NAVBAR_USER => ['onShowUser', 100],
ThemeEvents::THEME_SIDEBAR_USER => ['onShowUser', 100],
];
}
/**
* #param ShowUserEvent $event
* #throws \Exception
*/
public function onShowUser(ShowUserEvent $event)
{
if (null === $this->security->getUser()) {
return;
}
/** #var User $user */
$user = $this->security->getUser();
$event->setUser($user);
}
}
#templates/header/index.html.twig
<script type="text/javascript">
var user = {{ userJson | json_encode() | raw }};
</script>

How to use multiple routes and multiple param converter with Symfony

Is it possible to use ParamConverter with different classes depending on the route being called ?
Let's say I have a parent class Food with two children Fruit class and Vegetable class.
I would like to be able to do something like this:
/**
*
* #Route("fruit/{id}", name="fruit_show")
* #ParamConverter("food", class="AppBundle:Fruit")
* #Route("vegetable/{id}", name="vegetable_show")
* #ParamConverter("food", class="AppBundle:Vegetable")
*/
public function showAction(Food $food)
{ ... }
It seems like it is not possible to do exactly what you want. But it may be possible to get what you need with two simple wrapper actions. You won't even need an explicit #ParamConverter annotation. E.g.
/**
*
* #Route("fruit/{id}", name="fruit_show")
*/
public function showFruitAction(Fruit $fruit)
{
return $this->showAction($fruit)
}
/**
*
* #Route("vegetable/{id}", name="vegetable_show")
*/
public function showVegetableAction(Food $food)
{
return $this->showAction($vegetable)
}
public function showAction (Food $food)
{ ... }
The issue I found here is that the ParamConverter uses the last item in the annotations. If it matches the fruit_show route, the $food variable is an instance of the AppBundle:Vegetable class. That's the same if it matches the vegetable_show route.
class FoodController
{
/**
* #Route("/items/fruits/{id}", methods={"GET"}, name="fruits_show")
* #ParamConverter("food", class="AppBundle:Fruit")
* #Route("/items/vegetables/{id}", methods={"GET"}, name="vegetables_show")
* #ParamConverter("food", class="AppBundle:Vegetable")
*/
public function foodAction(Request $request, $food)
{
//
}
}
One workaround you can use is writing your own ParamConverter:
use Doctrine\ORM\EntityManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Symfony\Component\HttpFoundation\Request;
class FoodConverter implements ParamConverterInterface
{
protected $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function apply(Request $request, ParamConverter $configuration)
{
$id = $request->get('id');
$route = $request->get('_route');
$class = $configuration->getOptions()[$route];
$request->attributes->set($configuration->getName(), $this->entityManager->getRepository($class)->findOneById($id));
return true;
}
public function supports(ParamConverter $configuration)
{
return $configuration->getName() === 'food';
}
}
Adding it to your services:
services:
food_converter:
class: App\SupportClasses\FoodConverter
arguments: ['#doctrine.orm.entity_manager']
tags:
- {name: request.param_converter, priority: -2, converter: food_converter}
Using it like this:
class FoodController
{
/**
* #Route("/items/fruits/{id}", methods={"GET"}, name="fruits_show")
* #Route("/items/vegetables/{id}", methods={"GET"}, name="vegetables_show")
* #ParamConverter("food", converter = "food_converter" class="App:Food", options={"fruits_show" = "App:Fruit", "vegetables_show" = "App:Vegetable"})
*/
public function foodAction(Request $request, $food)
{
var_dump($food);
exit();
}
}

Symfony3- can´t access to collections data (get)

I have an object with several collection. I saved the data correctly and then, when I do "object->getCollection()", I didn´t obtain the data.
This are my entities:
Persona:
/**
* #ORM\OneToMany(targetEntity="PersonaDomicilio",mappedBy="idPersona",cascade={"persist"},orphanRemoval=true)
*/
public $domicilios;
public function __construct() {
$this->domicilios = new ArrayCollection();
}
public function getDomicilios() {
return $this->domicilios;
}
public function addDomicilio(PersonaDomicilio $persona_domicilio) {
$persona_domicilio->setIdPersona($this);
$this->domicilios[] = $persona_domicilio;
return $this;
}
public function removeDomicilio(PersonaDomicilio $persona_domicilio) {
$this->domicilios->removeElement($persona_domicilio);
}
PersonaDomicilio:
/**
* #var \AppBundle\Entity\Persona
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Persona",inversedBy="domicilios")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_persona", referencedColumnName="id_persona")
* })
*/
protected $idPersona;
The collections are null when I dump persona, and when I dump persona->getDomicilios() too.

Weird Doctrine ODM exception when using references together with inheritance

I've got three classes. The File-Class has a reference to Foobar and Game inherits from Foobar. There are some other Classes which also inherit from Foobar but i left them out as they aren't relevant here. I also left out some unrelevant fields and their getters and setters.
The plan is that every Game has two images, the mainImage and the secondaryImage. I've put those fields into a seperate class from which Game inherits because i need them for a few other classes too.
My problem is that if I load the games from the database as soon as i try to iterate over them I get the following exception:
Notice: Undefined index: in C:\xampp\htdocs\Symfony\vendor\doctrine\mongodb-odm\lib\Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo.php line 1293
For reference here are the lines of ClassMetadataInfo.php
public function getPHPIdentifierValue($id)
{
$idType = $this->fieldMappings[$this->identifier]['type'];
return Type::getType($idType)->convertToPHPValue($id);
}
Here are my classes
File-Class:
namespace Project\MainBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class File
{
/**
* #MongoDB\Id(strategy="INCREMENT")
*/
protected $id;
/**
* #MongoDB\ReferenceOne(targetDocument="Foobar", inversedBy="mainImage")
*/
private $mainImage;
/**
* #MongoDB\ReferenceOne(targetDocument="Foobar", inversedBy="secondaryImage")
*/
private $secondaryImage;
/**
* Get id
*/
public function getId()
{
return $this->id;
}
public function setMainImage($mainImage)
{
$this->mainImage = $mainImage;
return $this;
}
public function getMainImage()
{
return $this->mainImage;
}
public function setSecondaryImage($secondaryImage)
{
$this->secondaryImage = $secondaryImage;
return $this;
}
public function getSecondaryImage()
{
return $this->secondaryImage;
}
}
Foobar-Class:
namespace Project\MainBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\MappedSuperclass
*/
abstract class Foobar
{
/**
* #MongoDB\Id(strategy="INCREMENT")
*/
protected $id;
/**
* #MongoDB\ReferenceOne(targetDocument="File", mappedBy="mainImage")
*/
protected $mainImage;
/**
* #MongoDB\ReferenceOne(targetDocument="File", mappedBy="secondaryImage")
*/
protected $secondaryImage;
/**
* Get id
*/
public function getId()
{
return $this->id;
}
/**
* Set mainImage
*/
public function setMainImage($file)
{
$file->setMainImage($this);
$this->mainImage = $file;
return $this;
}
/**
* Get mainImage
*/
public function getMainImage()
{
return $this->mainImage;
}
/**
* Set secondaryImage
*/
public function setSecondaryImage($file)
{
$file->setSecondaryImage($this);
$this->secondaryImage = $file;
return $this;
}
/**
* Get secondaryImage
*/
public function getSecondaryImage()
{
return $this->secondaryImage;
}
}
Game-Class:
namespace Project\MainBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class Game extends Foobar
{
/**
* #MongoDB\String
*/
private $name;
/**
* Set name
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*/
public function getName()
{
return $this->name;
}
}
Though it doesn't really matter but here is my function i want to execute:
$dm = $this->get('doctrine_mongodb')->getManager();
$games_all = $dm->getRepository("ProjectMainBundle:Game")->createQueryBuilder()->sort('id', 'ASC')->getQuery()->execute();
foreach ($games_all as $singlegame) { // it breaks here
// Here i would do stuff
}
Is this a bug in Doctrine ODM or am I doing something wrong? Are the classes correct? I have tried everything but it just wont work.
I think it is too late for your question, but maybe there are other users having the same problem (as me).
The problem is related to Foobar being a MappedSuperclass. Had the same problem as described by you and at https://github.com/doctrine/mongodb-odm/issues/241.
Solution is to not reference the abstract class Foobar (=MappedSuperclass) but a concrete implementation (=Document) - as in your case - Game.
See also Doctrine ODM returns proxy object for base class instead of sub-classed document

Adding a file upload to a Symfony2 form throws an "Entity was not found" and a session is active error

I have a Symfony2 form that I want to add a file upload dialog to.
According to the Symfony docs (http://symfony.com/doc/2.0/cookbook/doctrine/file_uploads.html), I have created a Document class:
<?php
namespace Acme\AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Document
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
public $path;
/**
* #Assert\File(maxSize="6000000")
*/
public $file;
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return 'uploads/documents';
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
$this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set path
*
* #param string $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
}
And a DocumentType form class:
<?php
namespace Acme\AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class DocumentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\AppBundle\Entity\Document',
));
}
public function getName()
{
return 'document_form';
}
}
However, when I add this to my existing entity and form class:
<?php
namespace Acme\AppBundle\Entity\Profile;
use Doctrine\ORM\Mapping as ORM;
use Acme\AppBundle\Entity\jDocument;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="UserProfile")
*/
class UserProfile extends GenericProfile
{
//... Other entity params
/**
* #ORM\OneToOne(cascade={"persist", "remove"}, targetEntity="Acme\AppBundle\Entity\Document")
* #ORM\JoinColumn(name="picture_id", referencedColumnName="id", onDelete="set null")
*/
protected $picture;
/**
* Set picture
*
* #param Acme\AppBundle\Entity\Document $picture
*/
//\Acme\AppBundle\Entity\Document
public function setPicture($picture)
{
$this->picture = $picture;
}
/**
* Get picture
*
* #return Acme\AppBundle\Entity\Document
*/
public function getPicture()
{
return $this->picture;
}
//... Other entity getters and setters
}
Whenever I submit the form, I get the following error:
ErrorException: Warning: ini_set(): A session is active. You cannot change the session module's ini settings at this time in /var/www/wolseley-integrated-services/builds/dev/app/cache/prod/classes.php line 421
But the page title is "Entity was not found. (500 Internal Server Error)".
Can anybody spot which entity it can't find? Or if that's even the issue?
I've done some googling and checked that session.auto_start is set to 0 in php.ini, I've cleared all my sessions and caches... I'm stumped!
It turns out I was getting this strange session error message because of an error page definition in my nginx config.
The entity not found issue was resolved by correcting some errors in my entities. The Symfony developer bar provided me with enough information to track the issue down.

Resources