I have a code in Symfony 3.2, where I am trying to pass repository from Commmand class to my custom class, where I am running the websockets
<?php
namespace MyBundle\Command;
use MyBundle\Server\Notification;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ServerCommand extends ContainerAwareCommand
{
/**
* Configure a new Command Line
*/
protected function configure()
{
$this->setName('Project:notification:server')
->setDescription('Start the notification server.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$em = $this->getApplication()->getKernel()->getContainer()->get('My.repository.car');
$server = IoServer::factory(new HttpServer(
new WsServer(
new Notification($this->getContainer(),$em)
)
), 8080);
$server->run();
}
}
for All my db queries I am using repositories and there is no Entity. I have done this before, and it was working fine.
But now when I run command from terminal I am getting this error
Parse error: parse error in
/Applications/XAMPP/xamppfiles/htdocs/lavtaxi/src/MyBundle/Command/ServerCommand.php
on line 28
on line 28 there is
"$server = IoServer::factory(new HttpServer( " part
this is my services.yml
services:
My.repository.car:
class: MyBundle\Repository\CarRepository
arguments: ["#doctrine.orm.entity_manager"]
and this is Notification.php where I am trying to get data and send via sockets
<?php
namespace MyBundle\Server;
use Doctrine\ORM\EntityManager;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Notification implements MessageComponentInterface
{
protected $connections = array();
private $users = array();
protected $container;
private $drivers = array();
private $repository = null;
public function __construct(ContainerInterface $container, $em)
{
$this->repository = $em;
$this->container = $container;
$this->users = [];
$this->drivers = [];
}
/**
* A new websocket connection
*
* #param ConnectionInterface $conn
*/
public function onOpen(ConnectionInterface $conn)
{
$this->connections[] = $conn;
$this->users[$conn->resourceId] = $conn;
$this->drivers = $this->repository->getCarsData();
$conn->send('..:: Hello from the Notification Center ::..');
$conn->send(json_encode($this->drivers));
echo "New connection \n";
}
}
Error is disappears when I remove the repository calling part above, so I know that problem is not on IoServer
Related
I need to run the controller method every 2 hours. I read somewhere that you need to create a command and run this command by using CRON. It is correct?
MY COMMAND:
namespace AppBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Routing\Annotation\Route;
class RunCommand extends Command
{
// the name of the command (the part after "bin/console")
protected static $defaultName = 'app:run';
protected function configure()
{
// ...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
echo 'BEGIN';
$controller = new \AppBundle\Controller\DefaultController();
$controller->storeAction();
echo 'END';
}
}
MY CONTROLLER:
/**
* #Route("/to-db", name="to-db")
*/
public function storeAction()
{
$entityManager = $this->getDoctrine()->getManager();
$data = new Skuska();
$data->setName('Keyboard');
$entityManager->persist($data);
$entityManager->flush();
// die();
}
My error: In ControllerTrait.php line 424: Call to a member function has() on null
Is my code correct? How do I run a method using cron?
I don't want to use another bundle. I want to program it myself
As mentioned in the comments, you should move the logic out of the controller and into a service, and use that service both in the command and in the controller.
With the default service autoloading configuration, you don't even have to care about your service declarations. Your command will automatically be a service, and you can inject other services into it.
https://symfony.com/doc/current/console/commands_as_services.html
For controllers, you don't even need to use a specific constructor.
https://symfony.com/doc/current/controller.html#fetching-services
<?php
// AppBundle/Service/StoreService.php
use AppBundle\Entity\Skuska;
use Doctrine\ORM\EntityManager;
class StoreService
{
/** #var EntityManager */
private $entityManager;
/**
* StoreService constructor.
* #param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function store()
{
$data = new Skuska();
$data->setName('Keyboard');
$this->entityManager->persist($data);
$this->entityManager->flush();
}
}
<?php
// AppBundle/Controller/StoreController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Service\StoreService;
class StoreController extends Controller
{
/**
* #Route("/to-db", name="to-db")
* #param StoreService $storeService
* #return Response
*/
// Hinting to you service like this should be enough for autoloading.
// No need for a specific constructor here.
public function storeAction(StoreService $storeService)
{
$storeService->store();
return new Response(
// Return something in you response.
);
}
}
<?php
// AppBundle/Command/RunCommand.php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use AppBundle\Service\StoreService;
class RunCommand extends Command
{
protected static $defaultName = 'app:run';
/** #var StoreService */
protected $storeService;
/**
* RunCommand constructor.
* #param StoreService $storeService
*/
public function __construct(StoreService $storeService)
{
$this->storeService = $storeService;
parent::__construct();
}
protected function configure()
{
// ...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
echo 'BEGIN';
$this->storeService->store();
echo 'END';
}
}
I working on a web socket app using ratchet and symfony 2.8 to connect to database and changing value in a certain column if someone connect to the server but I get error in this line
$sql = $this->container->get('database_connection');
the full error message
An error has occurred: Notice: Undefined property: check\roomsBundle\Sockets\Chat::$container
my injection in the services.yml code
services:
database_connection:
class: check\roomsBundle\Sockets\Chat
arguments: ["#service_container"]
my Chat.php code
<?php
namespace check\roomsBundle\Sockets;
use tuto\testBundle\Entity\Users;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Chat implements MessageComponentInterface {
protected $clients;
//protected $db;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
$sql = $this->container->get('database_connection');
$users = $sql->query("UPDATE user SET ONoff= '1' WHERE UserId='2'");
}
}
Ok so there's a few things that you'll need to fix in order to solve your problem.
services:
database_connection:
class: check\roomsBundle\Sockets\Chat
arguments: ["#service_container"]
What this is doing is when it calls the constructor it's going to pass in the service container, however using the constructor to pass in your container isn't favorable, but rather instead you should implement the Symfony\Component\DependencyInjection\ContainerAwareInterface interface and then implement the method setContainer and optional a getContainer method.
/**
* #param ContainerInterface|NULL $container
*/
public function setContainer(
ContainerInterface $container = NULL
)
{
$this->container = $container;
return $this;
}
/**
* #return ContainerInterface
*/
protected function getContainer()
{
return $this->container;
}
And then after that update your service to call this method when initializing it.
services:
chat_service: # renamed because this is your chat service, not your database connection
class: check\roomsBundle\Sockets\Chat
calls:
- [setContainer, ["#service_container"]]
Your service is fine you just need little changes in your chat.php class
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class Chat implements MessageComponentInterface {
protected $clients;
private $container;
//protected $db;
public function __construct(Container $container) {
$this->clients = new \SplObjectStorage;
$this->container = $container;
}
Now u can use $this->container
Updated
Try to inject entity manager
services:
database_connection:
class: check\roomsBundle\Sockets\Chat
arguments:
- #doctrine.orm.default_entity_manager
in chat.php do like this
use Doctrine\ORM\EntityManager;
class Chat implements MessageComponentInterface {
protected $clients;
protected $em;
public function __construct(EntityManager $em) {
$this->clients = new \SplObjectStorage;
$this->em = $em;
}
$this->em->getRepository('yorrepo')->updateFuntion();
Now try to call from some repo to update
Injecting the service container is generally considered as a bad idea.
you should consider to inject database_connection service .
There are few ways to do that. Have a look at Types of Injection.
services:
chat_service:
class: check\roomsBundle\Sockets\Chat
arguments: ["#database_connection"]
your class
protected $connection;
public function __construct($connection) {
$this->connection = $connection;
}
Even if you want to go ahead with injecting the service container, the above link has relavent documentation that will help you to solve the issue you are facing.
I using symfony 2 and ratchet and memcache on a websocket chat project ratchet working good with symfony and i tested it on the "hello world" app on the offical web site docs
but the problem is when I run this line
new Chat(new MyApp(), $this->getContainer()),
i get this error
Attempted to load class "MyApp" from namespace
my command line code
<?php
// myapplication/src/sandboxBundle/Command/SocketCommand.php
// Change the namespace according to your bundle
namespace check\roomsBundle\Command;
use Ratchet\Session\SessionProvider;
use Symfony\Component\HttpFoundation\Session\Storage\Handler;
use Doctrine\Common\Cache\MemcacheCache;
use Ratchet\App;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
// Include ratchet libs
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
// Change the namespace according to your bundle
use check\roomsBundle\Sockets\Chat;
use Doctrine\ORM\EntityManager;
use Symfony\Component\HttpFoundation\Session\Session;
class WsServerCommand extends ContainerAwareCommand
{
protected function configure()
{
$this->setName('sockets:start-chat')
// the short description shown while running "php bin/console list"
->setHelp("Starts the chat socket demo")
// the full command description shown when running the command with
->setDescription('Starts the chat socket demo')
; }
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln([
'Chat socket',// A line
'============',// Another line
'Starting chat, open your browser.',// Empty line
]);
$memcache = new \Memcache;
$memcache->connect('localhost', 11211);
$session = new SessionProvider(
new Chat(new MyApp(), $this->getContainer()),
new Handler\MemcacheSessionHandler($memcache)
);
$server = new App('localhost');
$server->route('/sessDemo', $session);
$server->run();
}
}
the Chat.php code
<?php
namespace check\roomsBundle\Sockets;
use tuto\testBundle\Entity\Users;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Ratchet\WebSocket\WsServerInterface;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* This component will allow access to user data (FOSUserBundle)
* for each connection in your Ratchet application.
*/
class Chat implements MessageComponentInterface, WsServerInterface
{
/**
* #var \Ratchet\MessageComponentInterface
*/
protected $_app;
/**
* #var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $_container;
/**
* #param MessageComponentInterface $app
* #param ContainerInterface $container
*/
public function __construct(MessageComponentInterface $app, ContainerInterface $container)
{
$this->_app = $app;
$this->_container = $container;
}
/**
* {#inheritdoc}
*/
public function onOpen(ConnectionInterface $conn)
{
if (!isset ($conn->Session) || !$conn->Session instanceof Session) {
throw new \RuntimeException('Session is not defined. Make sure that SessionProvider is executed before FOSUserProvider.');
}
try {
$token = unserialize($conn->Session->get('_security_main'));
$user = $token->getUser();
$provider = $this->_container->get('fos_user.user_provider.username');
$conn->User = $provider->refreshUser($user);
} catch (Exception $ex) {
$conn->User = null;
}
return $this->_app->onOpen($conn);
}
There isn't any use MyApp; on the top of your page.
use AppBundle\Classes ?
I created a PHP class to generate some fixtures :
namespace DashboardBundle\DataFixtures\ORM;
use DashboardBundle\Entity\Property;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class LoadPropertyData extends AbstractFixture implements FixtureInterface, ContainerAwareInterface, OrderedFixtureInterface
{
/** #var ContainerInterface */
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function load(ObjectManager $manager)
{
$properties = $this->container->get('dashboard.properties_generator');
foreach ($properties as $key => $propertyConfig) {
$property = new Property();
$property->setName($key);
$property->setType($propertyConfig);
$this->addReference('property-' . $key, $property);
$manager->persist($property);
}
$manager->flush();
}
public function getOrder()
{
return 1;
}
}
But I get this error :
➜ dashboard git:(guillaume) ✗ bin/console -v fixtures:load
/* ... some stuff ... */
[Symfony\Component\Debug\Exception\FatalErrorException]
Compile Error: Cannot redeclare class DashboardBundle\DataFixtures\ORM\LoadPropertyData
The namespace seems and the class name seems correct. There is no other file in the DashboardBundle\DataFixtures\ORM directory.
I tried to restart the servers (PHP-FPM and Nginx), I tried to clear the Symfony cache, but there is no effect.
In brief, I have no idea why Symfony throws this exception.
Any idea ? Thanks !
I'm trying to expose some data with soap.
here's my controller holding the server (everything is normal here):
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Json\Json;
use Zend\Soap\Server;
use Zend\Soap\AutoDiscover;
class ExportController extends AbstractActionController
{
private $_options = array('soap_version' => SOAP_1_2);
private $_URI = '/export';
private $_WSDL_URI = '/export?wsdl';
private $wsdl;
public function indexAction() {
if (isset($_GET['wsdl'])) {
$this->handleWSDL();
} else {
$this->handleSOAP();
}
return $this->getResponse();
}
private function handleWSDL() {
$serverUrl = strtolower(dirname($_SERVER['SERVER_PROTOCOL']))."://".$_SERVER['HTTP_HOST'].":".$_SERVER['SERVER_PORT']."/Moving-BO/public";
$autodiscover = new AutoDiscover(new \Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence());
$autodiscover->setClass('Application\WebService\ExportClass')
->setUri($serverUrl.$this->_URI)
->setServiceName('MySoapService');
$autodiscover->handle();
$this->wsdl = $autodiscover->generate();
}
private function handleSOAP() {
$serverUrl = strtolower(dirname($_SERVER['SERVER_PROTOCOL']))."://".$_SERVER['HTTP_HOST'].":".$_SERVER['SERVER_PORT']."/Moving-BO/public";
$soap = new Server($serverUrl.$this->_WSDL_URI, $this->_options);
$soap->setClass('Application\WebService\ExportClass');
$soap->handle();
}
}
then here is the class I'm exporting:
namespace Application\WebService;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\ServiceManagerInterface;
use Doctrine\ORM\EntityManager;
use Zend\Json\Json;
use Parcours\Entity\Parcours;
class ExportClass implements ServiceLocatorAwareInterface
{
protected $em;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
public function setEntityManager(EntityManager $em)
{
$this->em = $em;
}
public function getEntityManager()
{
$this->em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
return $this->em;
}
/**
* Dit bonjour!
*
*
* #return string
*/
public function helloWorld(){
return 'coucou';
}
/**
* Retourne le titre d'un parcours
*
* #param integer $id
* #return array
*/
public function getParcours($id){
$parcours = $this->getEntityManager()->getRepository('Parcours\Entity\Parcours')->findOneBy(array('id'=>$id));
return $parcours->toArray();
}
}
I also have a test client, the first function: helloWorld() is working fine but the second one: getParcours($id) is returning the following error:
Call to a member function get() on a non-object
It seams like getServiceLocator() is returning null. I'm using a similar piece of code an AbstractActionController: ParcoursController which is working great. Why can't I do that here?
[EDIT]
Ok I've tried something else, instead of using the EntityManager in the ExportClass I've made a get function in my ParcoursController and call this function into the ExportClass. My ParcoursController is already using the EntityManager to display my data into pages so it should work. But the result is the same.
It seems like i should somehow pass my serviceLocator through the SOAP service. I don't think that's a good idea.
OK great I nailed it.
Here is my working conf, hope it helps someone.
All changes from the above example were:
A: added this to module.php (ExportModel is ExportClass from last example i just changed name and namespace)
return array(
'invokables' => array(
'Application\Model\ExportModel' => 'Application\Model\ExportModel',
),
)
B: I gave the instanciated model to my SoapServer
private function handleSOAP() {
$exportModel = $this->getServiceLocator()->get('Application\Model\ExportModel');
$serverUrl = strtolower(dirname($_SERVER['SERVER_PROTOCOL']))."://".$_SERVER['HTTP_HOST'].":".$_SERVER['SERVER_PORT']."/Moving-BO/public";
$soap = new Server($serverUrl.$this->_WSDL_URI, $this->_options);
$soap->setClass('Application\Model\ExportModel');
$soap->setObject($exportModel);
$soap->handle();
That's all.