I'm trying to run iFlyChat with Symfony using their PHP client https://iflychat.com/installation/php-chat-client which I have successfully install using composer.
I've created an extension for the code:
<?php
namespace DW\UserBundle\Twig;
use DW\UserBundle\Service\UserService;
use Iflylabs\iFlyChat;
class ChatExtension extends \Twig_Extension
{
/**
* #var UserService
*/
private $userService;
/**
* #var string
*/
private $appId;
/**
* #var string
*/
private $apiKey;
/**
* #param UserService $userService
* #param string $appId
* #param string $apiKey
*/
public function __construct(UserService $userService, string $appId, string $apiKey)
{
$this->userService = $userService;
$this->appId = $appId;
$this->apiKey = $apiKey;
}
/**
* #return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction("chat", [$this, "chat"])
];
}
public function chat()
{
$iflyChat = new iFlyChat($this->appId, $this->apiKey);
echo $iflyChat->getHtmlCode();
}
/**
* #return string
*/
public function getName()
{
return 'chat_extension';
}
}
but I get an error:
Attempted to load class "iFlyChat" from namespace "IFlyLabs". Did you
forget a "use" statement for another namespace?
Do I need to do something with the autoloader? I've been looking into registerPrefixes here but that doesn't exist anymore for Symfony3.2.
Have a look at vendor/composer/autoload_psr4.php so you can make sure there is an autoload namespace generated for IflyChat.
If there isn't you can execute:
composer dump-autoload
to force composer to regenerate the autoload for your dependencies.
It's because the file name does not match class name, it's installed as iflychat.php while the class is iFlyChat. Renaming the file to iFlyChat.php works.
Related
I am trying to inject an service object into my Repository. I have created different Service Classes under the directory Classes/Services. There is also one class that I created called ContainerService, which creates and instantiate one ServiceObject for each Service Class.
ContainerService Class:
namespace VendorName\MyExt\Service;
use VendorName\MyExt\Service\RestClientService;
class ContainerService {
private $restClient;
private $otherService;
/**
* #return RestClientService
*/
public function getRestClient() {
$objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
if ($this->restClient === null) {
$this->restClient = $objectManager->get(RestClientService::class);
}
return $this->restClient;
}
...
As I said, I create my ServiceObjects in the ContainerService Class.
Now I want to inject the ContainerService into my Repository and use it.
MyRepository Class:
namespace VendorName\MyExt\Domain\Repository;
use VendorName\MyExt\Service\ContainerService;
class MyRepository extends Repository
{
/**
* #var ContainerService
*/
public $containerService;
/**
* inject the ContainerService
*
* #param ContainerService $containerService
* #return void
*/
public function injectContainerService(ContainerService $containerService) {
$this->containerService = $containerService;
}
// Use Objects from The ContainerService
public function findAddress($addressId) {
$url = 'Person/getAddressbyId/'
$someData = $this->containerService->getRestClient()->sendRequest($url)
return $someData;
}
In MyController I recieve the $someData from my findAddress function and do some work with it.
But when I call my Page, I get following ErrorMessage:
(1/2) #1278450972 TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException
Class ContainerService does not exist. Reflection failed.
Already tried to reload all Caches and dumping the Autoload didn't help either.
Didn't install TYPO3 with composer.
I appreciate any advice or help! Thanks!
Actually found the Issue.
In MyRepository Class there was a Problem with the Annotations and the TypeHint:
namespace VendorName\MyExt\Domain\Repository;
use VendorName\MyExt\Service\ContainerService;
class MyRepository extends Repository
{
/**
*** #var \VendorName\MyExt\Service\ContainerService**
*/
public $containerService;
/**
* inject the ContainerService
*
* #param \VendorName\MyExt\Service\ContainerService $containerService
* #return void
*/
public function injectContainerService(\VendorName\MyExt\Service\ContainerService $containerService) {
$this->containerService = $containerService;
}
// Use Objects from The ContainerService
public function findAddress($addressId) {
$url = 'Person/getAddressbyId/'
$someData = $this->containerService->getRestClient()->sendRequest($url)
return $someData;
}
Now it works.
I have the following phpunit test for testing the controllers:
The DefaultControllerTest:
namespace Tests\AppBundle\Controller;
use Tests\AppBundle\Controller\BasicHttpController;
use AppBundle\DataFixtures\Test\DummyUserFixtures;
/**
* #testtype Functional
*/
class DefaultControllerTest extends BasicHttpController
{
/**
* {#inheritdoc}
*/
public function setUp()
{
$fixture = new DummyUserFixtures();
$fixture->load($this->entityManager);
}
/**
* Testing the Behavior when visiting the index page
*/
public function testIndex()
{
$client = $this->client;
$router=$client->getContainer()->get('router');
$crawler = $client->request('GET', '/');
$response=$client->getResponse();
$this->assertTrue($client->getResponse()->isRedirect());
$this->assertEquals($router->getRouteCollection()->get('fos_user_security_login')->getPath(),$response->headers->get('Location'));
//#todo Create Dummy Users
// $this->checkPanelAfterSucessfullLogin($crawler);
}
}
That extends the following test BasicHttpController (try to apply the DRY principle):
namespace Tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
class BasicHttpController extends WebTestCase
{
protected $entityManager=null;
protected $client=null;
/**
* {#inheritdoc}
*/
public function __construct()
{
parent::__construct();
$this->client = static::createClient();
$container = $this->client->getContainer();
$doctrine = $container->get('doctrine');
$this->entityManager=$doctrine->getManager();
}
/**
* Remove all entities from the database
*/
protected function truncateEntities()
{
$purger = new ORMPurger($this->entityManager());
$purger->purge();
}
/**
* {#inheritdoc}
*/
public function tearDown()
{
$this->truncateEntities();
}
/**
* #param username String the user's username
* #param passwoρd String the user's password
*/
protected function checkPanelAfterSucessfullLogin($crawler,string $username,string $password)
{
//Submitting the form
$form=$crawler->selectButton('_submit')->form();
$form['_username']=$username;
$form['_password']=$password;
$crawler=$crawler->submit($form);
$response=$client->getResponse();
$this->assertTrue($client->getResponse()->isRedirect());
$client->followRedirect();
//Checking header
$headerDom=$crawler->filter('header')->childen()->filter('nav.navbar')->children();
$this->assertCount(1,$headerDom->find('a.navbar-brand')); //homepage link
$this->assertCount(1,$headerDom->find('a.btn-danger')); //Logout button
}
}
As you can see I try to load the following fixture:
namespace AppBundle\DataFixtures\Test;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Common\Persistence\ObjectManager;
class DummyUserFixtures extends AbstractFixture implements OrderedFixtureInterface,ContainerAwareInterface
{
/**
* #var ContainerInterface
*/
private $container=null;
/**
* {#inheritDoc}
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* Generic function that creates a user with provided information.
* #param $name {String} The user's name
* #param $surname {String} The user's surname
* #param $username {String} The user's username
* #param $password {String} The user's password
* #param $email {String} The user's recovery email
* #param $role {String} The user's system role
* #param $phone {String | null} The user's phone number
* #param $organization {String|null} The user's organization
* #param $occupation {String|null} The user's occupation
*
* #return AppBundle\Entity\User
*/
private function createUser($name,$surname,$username,$password,$email,$role,$phone=null,$organization=null,$occupation=null)
{
$fosUserManager=$this->container->get('fos_user.user_manager');
/**
* #var AppBundle\Entity\User
*/
$user=$fosUserManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled(true);
$user->setRoles(array($role));
$user->setName($name);
$user->setSurname($surname);
if($phone){
$user->setPhone($phone);
}
if($organization){
$user->setOrganization($organization);
}
if($occupation){
$user->setOccupation($occupation);
}
$fosUserManager->updateUser($user, true);
return $user;
}
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager)
{
$this->createUser('John','Doe','jdoe','simplepasswd','jdoe#example.com','ROLE_USER','+3021456742324','Acme Products','Soft Engineer');
$this->createUser('Jackie','Chan','jchan','thesimplepasswd','jackiechan#example.com','ROLE_ADMIN','+302141232324','Holywood','Actor');
$this->createUser('Chuck','Norris','chuck_norris','unhackablepasswd','chucknorris#example.com','ROLE_SUPERADMIN',null,'Universe','Master');
}
public function getOrder()
{
return 1;
}
}
But for some reason I get the following error:
There was 1 error:
1) Tests\AppBundle\Controller\DefaultControllerTest::testIndex
Error: Call to a member function get() on null
/home/vagrant/code/src/AppBundle/DataFixtures/Test/DummyUserFixtures.php:50
/home/vagrant/code/src/AppBundle/DataFixtures/Test/DummyUserFixtures.php:87
/home/vagrant/code/tests/AppBundle/Controller/DefaultControllerTest.php:19
Further debugging has proved that the error is triggered by the following line in DummyUserFixtures:
$fosUserManager=$this->container->get('fos_user.user_manager');
So do you know how to load the data via fixtures?
In order to get it working you should set the service container you generate from the static::createClient() method and pass it via the $fixture->setContainer($container)
So a good approach is to define the container as protected instance variable to the BasicHttpController so any Test class (eg. the DefaultControllerTest in your case) is able to load the fixtures accordingly.
So using the setUp method and instance variables of BasicHttpController should be the following:
//Namespace declaration goes there
class BasicHttpController extends WebTestCase
{
protected $entityManager=null;
protected $client=null;
protected $container=null;
/**
* {#inheritdoc}
*/
public function setUp()
{
$this->client = static::createClient();
$this->container = $this->client->getContainer();
$doctrine = $this->container->get('doctrine');
$this->entityManager=$doctrine->getManager();
}
// Rest methods here
}
Note: on classes that are getting inherited from BasicHttpController you can define the setUp like that:
public function setUp()
{
parent::setUp();
// Add extra stuff here
}
So you can do more setUp bootstrapping before tests.
I'm following the tutorial : "How to customize a translatable Model?" in Sylius doc.
When I run the command : php bin/console doctrine:migrations:diff I got this error :
Fatal error: Declaration of AppBundle\Entity\ShippingMethod::createTranslation(): Sylius\Component\Shipping\Model\ShippingMethodTranslation must be compatible with Sylius\Component\Shipping\Model\ShippingMethod::createTranslation(): Sylius\Component\Shipping\Model\ShippingMethodTranslationInterface in C:\wamp64\www\acme7\src\AppBundle\Entity\ShippingMethod.php on line 8
Here is my class :
<?php
namespace AppBundle\Entity;
use Sylius\Component\Core\Model\ShippingMethod as BaseShippingMethod;
use Sylius\Component\Shipping\Model\ShippingMethodTranslation;
class ShippingMethod extends BaseShippingMethod
{
/**
* #var string
*/
private $estimatedDeliveryTime;
/**
* #return string
*/
public function getEstimatedDeliveryTime(): string
{
return $this->estimatedDeliveryTime;
}
/**
* #param string $estimatedDeliveryTime
*/
public function setEstimatedDeliveryTime(string $estimatedDeliveryTime): void
{
$this->estimatedDeliveryTime = $estimatedDeliveryTime;
}
/**
* {#inheritdoc}
*/
protected function createTranslation(): ShippingMethodTranslation
{
return new ShippingMethodTranslation();
}
}
Any idea on how to solved this ?
I got some help form the slack of sylius.
As I'm using Sylius v1.0.4
I had to replace :
use Sylius\Component\Shipping\Model\ShippingMethodTranslation;
by
use Sylius\Component\Shipping\Model\ShippingMethodTranslationInterface;
and
/**
* {#inheritdoc}
*/
protected function createTranslation(): ShippingMethodTranslation
{
return new ShippingMethodTranslation();
}
by
/**
* {#inheritdoc}
*/
protected function createTranslation(): ShippingMethodTranslationInterface {
return new ShippingMethodTranslation();
}
Trying to make an extension to the core db:seed command to add a couple of necessary options.
Extending the Illuminate\Database\Console\Seeds\SeedCommand
and registering my command in Kernel.php give me following output when running php artisan :
[Illuminate\Contracts\Container\BindingResolutionException]
Target [Illuminate\Database\ConnectionResolverInterface] is not instantiable while building [App\Console\Commands\TenantSeeder].
Any hints what I am missing ? the class itself below :
<?php
namespace App\Console\Commands;
use Illuminate\Database\Console\Seeds\SeedCommand;
use Illuminate\Console\ConfirmableTrait;
use Symfony\Component\Console\Input\InputOption;
use Illuminate\Database\ConnectionResolverInterface as Resolver;
class TenantSeeder extends SeedCommand
{
use ConfirmableTrait;
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'tenant:seed';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* The connection resolver instance.
*
* #var \Illuminate\Database\ConnectionResolverInterface
*/
protected $resolver;
/**
* Create a new database seed command instance.
*
* #param \Illuminate\Database\ConnectionResolverInterface $resolver
* #return void
*/
public function __construct(Resolver $resolver)
{
parent::__construct();
$this->resolver = $resolver;
}
public function getOptions()
{
$opts = parent::getOptions();
return array_merge($opts, [
['tenant', null, InputOption::VALUE_REQUIRED, 'Tenant is required to generate tenant-specific data'],
]);
}
}
You can do it like this if you are using a regular database like MySQL:
<?php
namespace App\Console\Commands;
use Illuminate\Database\Console\Seeds\SeedCommand;
use Illuminate\Database\DatabaseManager;
class CustomSeedCommand extends SeedCommand
{
public function __construct(DatabaseManager $databaseManager)
{
parent::__construct($databaseManager);
}
}
I am currently working on developing a project in SAAS, each client can access his platform by a personalized url (site1.com, site2.com, etc.).
For each domain name a set of template customization data is defined in the back office and I must be able to access it from my Twig files. So I defined a listener on the kernerl.request event that adds a global variable to Twig based on the current domain name. Everything works fine in most cases, except when a page is first displayed, Twig must be run upstream and I get the following error:
Unable to add global "site" as the runtime or the extensions have
already been initialized.
Listener class
class SiteListener
{
public function __construct(
SiteHelper $siteHelper,
\Twig_Environment $twig
) {
$this->siteHelper = $siteHelper;
$this->twig = $twig;
}
/**
* Add current contexts to twig global.
*/
public function addContextsToTwigGlobal(GetResponseEvent $event)
{
$this->twig->addGlobal('site', $this->siteHelper);
}
}
Listener service declaration
multisite.listener.site:
class: MultisiteBundle\Listener\SiteListener
arguments:
- "#multisite.helper.site"
- "#twig"
tags:
- { name: kernel.event_listener, event: kernel.request, method: addContextsToTwigGlobal }
SiteHelper service
class SiteHelper
{
/**
* #var RequestStack
*/
protected $requestStack;
/**
* #var ContextConfigManager;
*/
protected $contextConfigManager;
/**
* #var ContextConfig
*/
protected $contextConfig;
public function __construct(
RequestStack $requestStack,
ContextConfigManager $contextConfigManager
) {
$this->requestStack = $requestStack;
$this->contextConfigManager = $contextConfigManager;
$this->contextConfig = $this->contextConfigManager
->findByHostOrStandard($this->getHost());
}
/**
* Get host from current request.
*
* #return string|null
*/
public function getHost()
{
$request = $this->requestStack->getCurrentRequest();
return ($request) ? $request->getHost() : null;
}
/**
* Get current context config
*
* #return ContextConfig
*/
public function getContextConfig()
{
return $this->contextConfig;
}
}
Any idea ?
I decided to write a Twig function to avoid this kind of problem. This seem to be a good solution.
class SiteExtension extends \Twig_Extension
{
/**
* #var SiteHelper
*/
private $siteHelper;
/**
* Constructor.
*
* #param SiteHelper $siteHelper
*/
public function __construct(SiteHelper $siteHelper)
{
$this->siteHelper = $siteHelper;
}
/**
* {#inheritdoc}
*/
public function getFunctions()
{
return array(
new \Twig_Function('site', array($this->siteHelper, 'getContext')),
);
}
}