use Goutte\Client;
/**
* code removed
*/
class ......... {
public function xxxxxx() {
$client = new Client();
$client->getClient()->setDefaultOption('config/curl/'.CURLOPT_TIMEOUT, 60);
Gives error "Method setDefaultOption not found in class GuzzleHttp/Client"
Also code completion can not find the method.
Example is from https://github.com/FriendsOfPHP/Goutte
I am indeed on Guzzle~6 so this code worked:
$crawler = $client->request('GET', 'http://www.example.com',
['curl' => ['CURLOPT_TIMEOUT' => 60]]);
Related
I want to test a form via functional tests.
After filling in the form et then submit , the following error message was displayed :
[2020-06-11 17:45:32] request.CRITICAL: Uncaught PHP Exception LogicException: "Cannot set session ID after the session has started." at /var/www/renault-del/del/src/vendor/symfony/symfony/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php line 127 {"exception":"[object] (LogicException(code: 0): Cannot set session ID after the session has started. at /var/www/renault-del/del/src/vendor/symfony/symfony/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php:127)"} []
For information , this is my script that i used to sumit a form :
class CmsBlockControllerTest extends WebTestCase
{
/** #var Client */
private $client;
protected function setUp()
{
parent::setUp();
$this->client = static::createClient();
}
public function testNewAction(): void
{
$crawler = $this->client->request(
'GET',
$this->generateRoute('delbackoffice_cms_block_new') // my own function to generate a route
);
$form = $crawler->selectButton('Enregistrer')
->form([
'block[title]' => 'title',
'block[identifier]' => 'identifier',
'block[content]' => 'content']);
$this->client->submit($form);
}
protected function tearDown()
{
parent::tearDown();
$this->client = null;
$this->tokenStorage = null;
$this->globalVariables = null;
}
}
And thank you in advance
After a while, I found the solution by calling disableReboot on test.client.class in the following link : Solution here
So, i added $this->client->disableReboot(); after client creation. so it worked :)
First I will explain why and how the solution works and then the problems I have encountered. If you think there is a better way to do what I do, I'd love to hear it. I would also like to know why doctrine behaves in this way.
It turns out that my aplication needs to connect to a different database according to the client. I have a table, in a fixed database, containing the connection information that is used in some request.
I have had success with the following code:
class DynamicEntityManager {
protected $em;
private $request;
private $client_id;
public function __construct(RequestStack $request, EntityManagerInterface $em){
$this->em = $em;
$this->request = $request;
}
public function getEntityManager(ClientConn $client = null) {
$request = $this->request->getCurrentRequest();
if($client == NULL){
$domain = $request->attributes->get('domain');
if($domain == "" || $domain == NULL){
throw new \Exception("Error de conexion", 1);
}
$client = $this->em->getRepository(ClientConn::class)->findOneBy(array(
"subdomain" => $domain
));
if($client == NULL){
throw new \Exception("Error de conexion", 1);
}
}
$connectionDB = $client->getConnection();
$dbdriver = 'oci8';
$conexionSplit = explode(':',$connectionDB);
$dbhost = $conexionSplit[0];
$dbport = $conexionSplit[1];
$dbname = $conexionSplit[2];
$dbuser = $client->getUsuarioBd();
$dbpass = $client->getClaveBd();
$service = false;
$this->client_id = $client->getId();
if(strpos($dbname,'SN=') !== false){
$parts = explode('=',$dbname);
$dbname = $parts[1];
$service = true;
}
$request->attributes->set('client_id',$client->getId());
$conn = array(
'driver' => $dbdriver,
'host' => $dbhost,
'port' => $dbport,
'dbname' => $dbname,
'user' => $dbuser,
'password' => $dbpass,
'service' => $service,
'charset' => 'UTF8',
'schema' => null
);
return EntityManager::create($conn, $this->em->getConfiguration());
}
}
As you can see I return EntityManager::create($conn, $this->em->getConfiguration ()) with the new connection. The way I use it is the next:
/**
* #Route("/api/client/{id}/conf/{confID}", name="conf.show")
* #Method({"GET"})
*/
public function show(ClientConn $client, Request $request, DynamicEntityManager $dem ,$confId){
try {
$em = $dem->getEntityManager($client);
$entity = $em->getRepository(Configuration::class)->find($confId);
return new JsonResponse($entity, 200);
}
catch(\Exception $ex) {
return new JsonResponse([
"excepcion" => $ex->getMessage()
], $ex->getCode());
}
}
It works as expected or so I believed until I saw that when the entity has a custom repository it is unable to use the dynamic connection and therefore the previous route will return a table not found exception.
#ORM\Entity() <-- Works like a charm
#ORM\Entity(repositoryClass="App\Repository\ConfigurationRepository")<-- Table not found.
It works in the repository if I create the connection again, although I do not like the solution. So, what do I want? I would like to be able to use the basic methods like find (), findBy () and others without having to rewrite them every time I use a custom repository.
class ConfigurationRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry, DynamicEntityManager $dem)
{
parent::__construct($registry, Configuration::class);
$this->dem= $dem;
}
public function uglyFind($client, $confID)
{
$query = $this->dem->getEntityManager($client)->createQueryBuilder('conf')
->select("conf")
->from(ConfPedidosLentes::class,'conf')
->where('conf.id = :value')->setParameter('value', $confID)
->getQuery();
return $query->getOneOrNullResult();
}
I will really appreciate any contribution and thought in this matter.
Instead of:
class ConfigurationRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry, DynamicEntityManager $dem)
{
parent::__construct($registry, Configuration::class);
$this->dem= $dem;
}
...
try extending EntityRepository (without using a constructor) and use find as you did in your controller:
use Doctrine\ORM\EntityRepository;
class ConfigurationRepository extends EntityRepository
{
}
ServiceEntityRepository is an optional EntityRepository base class with a simplified constructor for autowiring, that explicitly sets the entity manager to the EntityRepository base class. Since you have not configured your doctrine managers to handle these connections properly (it's not even possible actually with so many connections), ServiceEntityRepository will pass a wrong EntityManager instance to the EntityRepository subclass, that's why you should not extend ServiceEntityRepository but EntityRepository.
I am receiving the following error
[2018-12-18 12:12:46] local.ERROR: Credentials are required to create a Client {"exception":"[object] (Twilio\Exceptions\ConfigurationException(code: 0): Credentials are required to create a Client at C:\wamp64\www\_javid\javid\vendor\twilio\sdk\Twilio\Rest\Client.php:157)
I will include the code below and the source i used to create it. I would like to add, this was all working correctly the other evening.
Today, i merely added a new function to handle the saving of messages to the database. Then i started receiving the above error. Naturally i reverted my changes but still the same error.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Auth;
use JWTAuth;
use App\Item;
use Log;
use Twilio\Rest\Client;
class MessagingController extends Controller
{
protected $client;
public function __construct(Client $client){
$this->client = $client;
}
/**
* Show the form for creating a notification.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('notifications.create');
}
public function sendMessage(request $request){
$details = $request->only('membershipNumber', 'countryCode', 'message');
$user = User::where('membership_number', $details['membershipNumber'])->with('mobile_number')->first();
if(count($user)>0){
$this->messageSaveToDatabase($details, $user);
$this->messageSendToMobile($details, $user);
$this->messageSendToEmail($details, $user);
return response([
'status' => 'success',
'msg' => __('messages.success'),
'response' => $details
], 200);
} else {
return response([
'status' => 'error',
'msg' => __('messages.error')
], 200);
}
}
protected function messageSaveToDatabase($details, $user){
}
protected function messageSendToMobile($details, $user, $imageUrl = null){
$lineBreak = "\n\n";
$phoneNumber = $user->mobile_number->country_code.decrypt($user->mobile_number->number);
$message = "Hi member #".$details['membershipNumber'].$lineBreak.
$details['message'];
$twilioPhoneNumber = config('services.twilio')['phoneNumber'];
$messageParams = array(
'from' => $twilioPhoneNumber,
'body' => $message
);
if ($imageUrl) {
$messageParams['mediaUrl'] = $imageUrl;
}
$this->client->messages->create(
$phoneNumber,
$messageParams
);
}
protected function messageSendToEmail($details, $user){
}
}
I have checked the TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN, these are both correct.
The code was taken from the following guide, i stripped out the subscriber part. Guide from Twilio
one more thing, I found the following Here which suggests i need to do something like this $client = new Client($keySid, $keySecret, $accountSid); but the guide above, does not do this, plus it all worked like this also.
Any help or suggestions would be great, i'm running out of hair to pull out :(
After a little more googling and some re-working, I found a working solution
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Auth;
use Twilio\Rest\Client;
class MessagingController extends Controller
{
protected function messageSendToMobile($details, $message, $user, $imageUrl = null){
$accountSid = env('TWILIO_ACCOUNT_SID');
$authToken = env('TWILIO_AUTH_TOKEN');
$twilioNumber = env('TWILIO_PHONE_NUMBER');
$lineBreak = "\n\n";
$to = $user->mobile_number->country_code.decrypt($user->mobile_number->number);
$client = new Client($accountSid, $authToken);
try {
$client->messages->create(
$to,
[
"body" => $message,
"from" => $twilioNumber
]
);
Log::info('Message sent to ' . $twilioNumber);
} catch (TwilioException $e) {
Log::error(
'Could not send SMS notification.' .
' Twilio replied with: ' . $e
);
}
}
}
I'm trying to test a form but i got unreachable field exception.
My controller's code :
class StudentController extends Controller
{
/**
* #Route("/student/new",name="create_new_student")
*/
public function newAction(Request $request){
$student = new Student();
$form = $this->createFormBuilder($student)->add('name',TextType::class)
->add('save',SubmitType::class,['label' => 'Create student'])->getForm();
$form->handleRequest($request);
if($form->isSubmitted()){
$student = $form->getData();
$name = $student->getName();
echo "Your name is ".$name;
die();
}
return $this->render(':Student:new.html.twig',['form' => $form->createView()]);
}
}
My StudentControllerTest :
class StudentControllerTest extends WebTestCase
{
public function testNew(){
$client = static::createClient();
$crawler = $client->request('POST','/student/new');
$form = $crawler->selectButton('Create student')->form();
$form['name'] = 'Student1';
$crawler = $client->submit($form);
$this->assertGreaterThan(0,$crawler->filter('html:contains("Your name is Student1")')->count());
}
}
When i run the test using phpunit i got :
InvalidArgumentException: Unreachable field "name"
I'm following the tutorial from https://symfony.com/doc/current/testing.html
You should use the $form['form_name[subject]'] syntax
public function testNew(){
$client = static::createClient();
//you should request it with GET method, it's more close to the reality
$crawler = $client->request('GET','/student/new');
$form = $crawler->selectButton('Create student')->form();
$form['form_name[name]'] = 'Student1';
// [...]
}
Try this way. Edit Test
$form = $crawler->selectButton('Create student')->form(['name' => 'Student1']);
Edit Controller:
...
$name = $student->getName();
return new Response("Your name is ". $name);
Do not kill what Symfony request.
I try to do a functional test on a controller that executes doctrine. When I execute my test, it fails. but when I commented in my controller this line:"$products = $em->getRepository("Couture\FrontBundle\Entity\Produit")->findAll()".
my test is success.
this is my controller:
class ProductController extends Controller {
/**
* Get products
* #Route("/products")
* #Method("GET")
*/
public function getAllAction() {
$serialize = $this->get('jms_serializer');
$em = $this->getDoctrine();
$products = $em->getRepository('Couture\FrontBundle\Entity\Produit')->findAll();
if (!$products) {
$response = new Response(json_encode(array('error' => 'Resources not found for products')));
$response->headers->set('Content-Type', 'application/json');
$response->setStatusCode('400');
return $response;
}
$response = new Response($serialize->serialize($products, 'json'));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
this is my class test:
class ProductControllerTest extends WebTestCase {
public function testGetAll() {
$client = static::createClient();
$client->request('GET', $client->getContainer()->get('router')->generate('couture_front_product_getall'));
$this->assertEquals(
200, $client->getResponse()->getStatusCode()
);
}
}
When you comment that line, !$products is false and then your controller return a Reponse object with application/json content-type header. This response is considered as successful because its status code is 200 OK.
What I have seen in such scenario, is the use of data fixtures to test entities managed by doctrine entityManager.
Your test class may look like this ( not tested code, just to give you the idea behind):
class ProductControllerTest extends WebTestCase {
public function testGetAll() {
$client = static::createClient();
$fixtures = array('Acme\YourBundle\dataFixtures\LoadProductData');
$this->loadFixtures($fixtures);
$uri= $this->getUrl('couture_front_product_getall');
$crawler= $client->request('GET',$uri);
$this->assertEquals(200,$client->getResponse()->getStatusCode() );
}
}