Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This course is archived!
This tutorial uses a deprecated micro-framework called Silex. The fundamentals of REST are still ? valid, but the code we use can't be used in a real application.

POST: Creation, Location Header and 201

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

POST: Creation, Location Header and 201

Once the POST endpoint works, the client will send programmer details to the server. In REST-speak, it will send a representation of a programmer, which can be done in a bunch of different ways. It’s invisible to us, but HTML forms do this by sending data in a format called application/x-www-form-urlencoded:

POST /api/programmers HTTP/1.1
Host: localhost:8000
Content-Type: application/x-www-form-urlencoded

nickname=Geek+Dev1&avatarNumber=5

PHP reads this and puts it into the $_POST array. That’s ok for the web, but in the API world, it’s ugly. Why not, have the client send us the representation in a beautiful bouquet of curly braces known as JSON:

POST /api/programmers HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
    "nickname": "Geek Dev1",
    "avatarNumber": 5
}

Creating a request like this with Guzzle is easy:

// testing.php
// ...

$nickname = 'ObjectOrienter'.rand(0, 999);
$data = array(
    'nickname' => $nickname,
    'avatarNumber' => 5,
    'tagLine' => 'a test dev!'
);

$request = $client->post('/api/programmers', null, json_encode($data));
$response = $request->send();

echo $response;
echo "\n\n";

The second null argument is the request headers to send. We’re not worried about headers yet, so we can just leave it blank.

Coding up the Endpoint

Back in the ProgrammerController class, let’s make this work by doing our favorite thing - coding! First, how do we get the JSON string passed in the request? In Silex, you do this by getting the Request object and calling getContent() on it. Let’s just return the data from the endpoint so we can see it:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function newAction(Request $request)
{
    $data = $request->getContent();
    return $data;
}

Tip

Your framework will likely have a shortcut for getting the request content or body. But if it doesn’t, you can get it by using this strange bit of code:

$data = file_get_contents('php://input');

This is a special stream that reads the request body. For more details, see php.net: php://.

Try running our testing.php file again:

$ php testing.php

This time, we see the JSON string being echo’ed right back at us:

HTTP/1.1 200 OK
...
Content-Type: text/html; charset=UTF-8

{"nickname":"ObjectOrienter31","avatarNumber":5}

Creating the Programmer Resource Object

Awesome! I’ve already created a Programmer class, which has just a few properties on it. I also created simple classes for the other two resources - Project and Battle. We’ll use these later.

In newAction, we have the JSON string, so let’s decode it and use the data to create a new Programmer object that’s ready for battle. We’ll use each key that the client sends to populate a property on the object:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function newAction(Request $request)
{
    $data = json_decode($request->getContent(), true);

    $programmer = new Programmer($data['nickname'], $data['avatarNumber']);
    $programmer->tagLine = $data['tagLine'];
    // ...
}

Note

Do not forget to add use KnpU\CodeBattle\Model\Programmer; namespace for the Programmer class at the beginning of the ProgrammerController.php.

My app also has a really simple ORM that lets us save these objects to the database. How you save things to your database will be different. The key point is that we have a Programmer class that models how we want our API to look, and that we can somehow save this:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function newAction(Request $request)
{
    $data = json_decode($request->getContent(), true);

    $programmer = new Programmer($data['nickname'], $data['avatarNumber']);
    $programmer->tagLine = $data['tagLine'];
    $programmer->userId = $this->findUserByUsername('weaverryan')->id;

    $this->save($programmer);

    return 'It worked. Believe me - I\'m an API';
}

At the bottom, I’m just returning a really reassuring message that everything went ok.

Faking the Authenticated User

I’ve also added one really ugly detail:

$programmer->userId = $this->findUserByUsername('weaverryan')->id;

Every programmer is created and owned by one user. On the web, finding out who is creating the programmer is as easy as finding out which user is currently logged in.

But our API has no idea who we are - we’re just a client making requests without any identification.

We’ll fix this later. Right now, I’ll just make every programmer owned by me. Make sure to use my username: it’s setup as test data that’s always in our database. This test data is also known as fixtures.

Ok, the moment of truth! Run the testing script again:

$ php testing.php
HTTP/1.1 200 OK
Host: localhost:8000
...
Content-Type: text/html; charset=UTF-8

It worked. Believe me - I'm an API

The message tells us that it probably worked. And if you login as weaverryan with password foo on the web, you’ll see this fierce programmer-warrior in the list.

Status Code 201

But no time to celebrate! Our response is a little sad. First, since we’ve just created a resource, the HTTP elders say that we should return a 201 status code. In Silex, we just need to return a new Response object and set the status code as the second argument:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function newAction(Request $request)
{
    // ...
    $this->save($programmer);

    return new Response('It worked. Believe me - I\'m an API', 201);
}

Running the testing script this time shows us a 201 status code.

Location Header

And when we use the 201 status code, there’s another rule: include a Location header that points to the new resource. Hmm, we don’t have an endpoint to get a single programmer representation yet. To avoid angering the RESTful elders, let’s add a location header, and just fake the URL for now:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function newAction(Request $request)
{
    // ...
    $this->save($programmer);

    $response = new Response('It worked. Believe me - I\'m an API', 201);
    $response->headers->set('Location', '/some/programmer/url');

    return $response;
}

If you stop and think about it, this is how the web works. When we submit a form to create a programmer, the server returns a redirect that takes us to the page to view it. In an API, the status code is 201 instead of 301 or 302, but the server is trying to help show us the way in both cases.

Try the final product out in our test script:

$ php testing.php
HTTP/1.1 201 Created
...
Location: /some/programmer/url
Content-Type: text/html; charset=UTF-8

It worked. Believe me - I'm an API

Other than the random text we’re still returning, this endpoint is looking great. Now to GET a programmer!

Leave a comment!

80
Login or Register to join the conversation

hey guys! I dont quite know where to ask this, so I'll ask here.

I'm trying to POST a json body request to an external url API based on Graphql


$response = $client->request(
                'POST',
                'https://URL', [
                'headers' => [
                    'Accept' => 'application/json',
                ],
                'body' => '{
    "operationName": "whatever",
    "variables": {
        "from": 0,
        "size": 24,
        "owner": $variable,
        "criteria": {}
    },
    "query": "query whatever($criteria: SearchCriteria, $from: Int, $sort: SortBy, $size: Int, $owner: String) {\n  type(criteria: $criteria, from: $from, sort: $sort, size: $size, owner: $owner) {\n    total\n    results {\n      ...whatever\n     }\n   }\n}\n\nfragment whatever on Response {\n  id\n  name\n  class\n  image\n  parts {\n    name\n    class\n    type\n    }\n  }\n"
}',
            ]);

            dd($response);

but I keep getting bad request response (HTTP/1.1 400 Bad Request returned for ).... I am very very new to the httpclientinterface and httpclient as a whole. so any pointers on how to do this would be amazing.

Reply

Hey jlchafardet!

Hmm, I'm not sure. When that external API returns this 400 error, it should include details about what went wrong... it could many different things, like the "body" is malformed, or the data is formed correctly, but some key in their doesn't make sense to the API.

But, I do notice that you're creating the JSON manually... which (as long as you haven't made any syntax errors) is fine, just a lot of work :). You would normally use the json option instead of body for this and set it to an array. This is mentioned in this section - https://symfony.com/doc/current/http_client.html#uploading-data - inside a box if you scroll a little.

Cheers!

Reply

I am still learning about the whole httpclient and httpclientinterface, yes I tried using the json type instead of "body", but got the same error.

I think all I need is to read a little more and dedicate a little extra time to it instead of being as impatient as I'm being right now :D

Reply
Default user avatar
Default user avatar Thierno Diop | posted 5 years ago

when i execute the testing.php file i am redirected to the login page is it normal ?

Reply
Default user avatar

oki its good it was because in scurity.yml the A in api was writen in capital

Reply
Default user avatar
Default user avatar Maksym Minenko | posted 5 years ago

Why is this on the Symfony *3* track, I wonder?

Reply

Hey Maksym!

We have it because it's still relevant (the changes from Symfony 2 to 3 - other than the directory structure changes - are quite minor). We have a few other things on the Symfony 3 track that are done with later versions of Symfony 2, but are still relevant. And in this case, we *do* switch to Symfony 3 during Course 4 - so the series is a bit mixed!

Cheers!

Reply
Default user avatar
Default user avatar Prakash | posted 5 years ago

Hello how i do the REST API with syfmony 3.* version. currently example is with symfony 2.6. how i can migtae to syfmony 3?

Reply

Hey Prakash,

Everything is mostly the same. First of all you need to upgrade composer dependencies according to the Symfony 3. To do that, you should ensure that bundles you use in project support Symfony 3.x, check its composer.json file to see symfony/framework-bundle: ^2.0 || ^3.0. If you see "^3.0" - it should work and you can do upgrade.
P.S. Don't forget to fix all deprecations in 2.8 before upgrading. We have a tutorial about it: <a href="http://knpuniversity.com/screencast/symfony3-upgrade&quot;&gt;
How to Upgrade to Symfony 2.8, then 3.0</a>.

Cheers!

Reply

In my testing.php i had to make the line $response = $client->post('/app_dev.php/api/programmers'); How do I change that?

Reply

Hi Scott!

Because you're using Symfony, if you use the built-in web server command from Symfony (php app/console server:run) it will start a built-in web server where it *defaults* to using app_dev.php - without you needing to have it in the URL. Alternatively, you can setup any other web server locally to have the same behavior.

BUT, more generally, we do talk about this in our Symfony REST tutorial. In our tests, we use a hook into Guzzle that automatically prepends the URL: http://knpuniversity.com/sc.... In episode 4 (which I'm recording right now), I've updated the code that hooks into Guzzle to work for Guzzle version 6: http://knpuniversity.com/sc...

I hope that helps - good question!

Reply
Default user avatar

That helped me!! i couldn't navigate the website so i changed nginx to serve app_dev.php and its working. But isn't there a way to prepend all routes with /app_dev.php within symfony?

thanks!

Reply

Awesome! So, whether or not you need the app_dev.php is *all* about your web server :). Ultimately, if you want the "dev" environment to be executed, then the web/app_dev.php must be executed. As I mentioned earlier, if you use the built-in web server with Symfony, it pre-configures things so that you *don't* need the app_dev.php at the beginning of all of the URLs: if there is no file in the URL, then it is "rewritten" to use app_dev.php. If you use Apache, for example, you could setup rewrite rules locally to do the same. In fact, there is a web/.htaccess file that sets up rewrite rules in Apache so that app.php is used by default (which is what you want in production). I know a lot of people that setup their web server locally to automatically rewrite to app_dev.php so that they don't need to have it in their URL.

Cheers!

Reply
Default user avatar

Thank you pointing in the right direction! Although by just changing only the nginx/sites-enabled/restexample.dev i had some troubles (404 errors) with testing env because i think the real path was "domain/app_dev.php/app_test.php/api/whatever" but Victors(knp) advice in video13/course1 helped me. i will try to manipulate paths from .htaccess from now on but so long all ok.

Reply
Default user avatar

When I did a composer install, I did receive a ton of deprecation notices. But the app runs except in the browser console it says GET http://localhost:8000/vendor/font-awesome/fonts/fontawesome-webfont.ttf?v=4.0.3 404 (Not Found)

Reply

Hey John!

Yep - there are a few libraries that still work fine, but are older versions at this point. The only one that I know is actually *deprecated* is Guzzle. We use guzzle/guzzle at version 3, but the latest version os guzzlehttp/guzzle (yes it has a different name now) at version 6! We don't technically use this library for the API... but we do use it for *testing* the API. In the Symfony REST tutorial - starting on episode 4 (http://knpuniversity.com/sc... we use the latest and greatest version 6. So, if you're curious about the differences, you can compare. Otherwise, if you're here for the API stuff, I wouldn't worry about it :).

About the 404 on the Font file, I'm not sure about that. If you download the starting code, there *is* a web/vendor/font-awesome/fonts/fontawesome-webfont.ttf file in the project - so it should be loading this just fine. It shouldn't affect anything either way (you might just be missing some cute icons) but the 404 is mysterious!

Cheers!

Reply
Default user avatar

Hello! I get the following error: Catchable fatal error: Object of class GuzzleHttp\Psr7\Response could not be converted to string in \testing.php on line 37. there is "echo $response". how should I convert my response object to string?

Reply

Hey Andjii!

The tutorial uses guzzle/guzzle version 3.7, not guzzlehttp/guzzle at version 6 (which I'm guessing you are using). You can use the old, guzzle/guzzle just fine, or use the new library. But in that case, you'll need to do a little bit of translating for the new version of the library. Check out this comment for a few more details, including a gist with a version of testing.php that should work with the latest version :). http://knpuniversity.com/screencast/rest/post#comment-2298542838

But, to finally answer your question, you can't just echo the $response in Guzzle 6 (as you know), but you can print the body:


echo $response->getBody();

In some ways, the new version of the library is not as user-friendly as the old version. You can also check out this Response debugging function that we use in the Symfony REST tutorial: https://gist.github.com/weaverryan/8bcf209fe11290b01185195280661e97#file-apitestcase-php-L130

Cheers!

Reply
Default user avatar
Default user avatar Roberto Briones Argüelles | posted 5 years ago

Why is better option to use the `testing.php` file instead Postman? Seems dirty to me.

Reply

Hi Roberto!

Actually, I would argue that testing.php is not better than Postman :). However, we will soon (in the next chapters in this tutorial) take the code from testing.php and turn them into true functional tests for our API. I believe this *is* better than Postman, because we now have a test suite that we can run at any time.

Cheers!

1 Reply
Default user avatar
Default user avatar Yan Yong | posted 5 years ago

Hello, where this is config file for setting up the database connection? I called $this->save($programmer), but it wasn't showing up.

Reply

Hey Yan,

I suppose if your DB credentials were invalid - you'll get a 500 error. Probably, you have permissions problem, we use SQLite for this course. The DB configuration is located in "src/KnpU/CodeBattle/Application.php" - see configureParameters() method. Make sure "data/code_battles.sqlite" file exist and have read/write permissions. Or you can simply change drive to pdo_mysql and fill MySQL credentials to use MySQL db instead.

Cheers!

Reply
Default user avatar

Hi Victor,
I have code_battles.sqlite, and the whole data directory got 777 permission. test.php runs without error or exception. Still not saving anything.

so I update the configureProviders() function to use mysql. Then when I visit localhost:8000/login, I got 2002 error.
"An exception occured in driver: SQLSTATE[HY000] [2002] No such file or directory"

I check the database, its empty. How can I get the schema? Usually, I do that via the symfony console doctrine:schema:update, but there is no such tool.

Reply

Hey Yan,

An exception occured in driver: SQLSTATE[HY000] [2002] No such file or directory

You configure MySQL credentials incorrectly. Here's the correct parameters, you should fill them in with your correct credentials:


        // Doctrine DBAL
        $this->register(new DoctrineServiceProvider(), array(
            'db.options' => array(
                'driver'   => 'pdo_mysql',
                'host' => 'localhost',
                'port' => 3306,
                'dbname' => 'rest',
                'user' => 'root',
                'password' => '',
            ),
        ));

The "path" option is something unique for SQLite, so you don't need to use it for MySQL database.

About schema, yeah, that's the worst part - you need to create it manually because this application do not have Symfony console support. That's why all the schema and initial data are commited to the repository, i.e. lies in the data/code_battles.sqlite file.

Cheers!

Reply
Default user avatar

Hello
When I run in cmd: composer install
I have error

Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap declared at C:\OpenServer\domains\start.symfony.rest\vendor\sensio\distribution-bundle\Sensio\Bundle\DistributionBundle\Composer\ScriptHandler.php accepts a Composer\Script\CommandEvent but post-install-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc... in phar://C:/OpenServer/modules/php/PHP-7.0-x64/composer.phar/src/Composer/EventDispatcher/EventDispatcher.php:316

How can I to fix this notice?

Reply

Hey Nina

Try updating composer and then the dependency


composer self-update
composer update sensio/distribution-bundle

Cheers!

Reply
Shaun T. Avatar
Shaun T. Avatar Shaun T. | posted 5 years ago

In the symfony documentation they don’t use Guzzle for functional tests and they extended webtestcase. Is this the best practice now?

https://symfony.com/doc/cur...

Reply

Hey Shaun,

Yes, Symfony recommends this way. But if you like Guzzle a lot - you can use Guzzle of course ;)

Cheers!

Reply
Default user avatar
Default user avatar Igor Kalamurda | posted 5 years ago

please don't do zooming file view, becouse sometimes loosing and dont understand what file is edit author, so need go back to find out what file currently is

Reply

Hey Igor Kalamurda!

Good feedback! We actually don't zoom anymore on newer videos - glad that's preferable :).

Cheers!

Reply
Default user avatar
Default user avatar Henri Tompodung | posted 5 years ago

Hi everyone.. I get this error:
PHP Fatal error: Uncaught Error: Class 'GuzzleHtpp\Client' not found in /home/henri/myprojects/symfonyrest/testing.php:5
Stack trace:
#0 {main}
thrown in /home/henri/myprojects/symfonyrest/testing.php on line 5

and this is my testing.php :

'http://localhost:8000',
'defaults' => [
'exceptions' => false,
]
]);

$response = $client->post('/api/programmers');

echo $response;
echo "\n\n";

any suggestion?

Reply

Yo Henry,

I think it was just a misprint :) Look closely to "GuzzleHtpp" - it should be "GuzzleHttp", i.e. "GuzzleHttp\Client".

Cheers!

Reply
Default user avatar
Default user avatar Henri Tompodung | Victor | posted 5 years ago | edited

Ups.. sorry my bad! >.<
Thank you victor

Reply
Shaun T. Avatar
Shaun T. Avatar Shaun T. | posted 5 years ago | edited

For anyone using Guzzle version 6, this is what I used to get this working:


require __DIR__.'/vendor/autoload.php';

$client = new \GuzzleHttp\Client([
    'base_uri' => 'http://localhost:8000',
    'defaults' => [
        'exceptions' => false,
    ]
]);

$response = $client->post('/api/posttests');

echo $response->getStatusCode() . ' ' . $response->getReasonPhrase();
echo "\n";
foreach ($response->getHeaders() as $name => $values) {
    echo $name . ': ' . implode(', ', $values) . "\r\n";
}
echo $response->getBody();
echo "\n\n";
Reply

Hey Shaun,

Thanks for sharing it with others. Yes, you need to use "base_uri" now, but why do you set exceptions to false? And why do you echo all that info? Is it just temporary for debugging purposes?

Cheers!

Reply
Shaun T. Avatar
Shaun T. Avatar Shaun T. | posted 5 years ago

When I try to run testing.php I get the following error:

Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$ php testing.php

Fatal error: Cannot use lexical variable $eventName as a parameter name in /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/guzzlehttp/guzzle/src/Event/Emitter.php on line 48

Reply

Hey Shaun T.!

Ah, unfortunately, it looks like a bug in Guzzle and PHP 7! https://github.com/guzzle/g....

What version of Guzzle are you using? I believe this bug was fixed in 5.3.1 (and was not present in 6).

Cheers!

Reply
Shaun T. Avatar

Thanks Ryan, I'm not sure how I can check as I don't see it in my composer.json...

Reply

Hey Shaun,

You can see a lot of information by executing "composer info package_name" command, e.g. to see the version of guzzlehttp/guzzle, run:

composer info "guzzlehttp/guzzle"

Cheers!

Reply
Shaun T. Avatar

Thanks @Ryan and @Victor, how can I update the Guzzle version if it's not in composer.json ?

I tried:

Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$ composer update vendor/guzzlehttp:5.3.1
Package "vendor/guzzlehttp:5.3.1" listed for update is not installed. Ignoring.
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update

Reply

Hey Shaun T.!

Hmm, interesting! I wonder if the Guzzle bug also exists in the older version that we're using in this tutorial. What do you see when you run these 2 commands?

```
composer info "guzzlehttp/guzzle"
composer info "guzzle/guzzle"
```

We'll figure this out! If there *is* an old bug with the version of Guzzle we're using in this tutorial, then unfortunately, the best solution will be to use a newer version of Guzzle. That's only annoying because it means that code in this tutorial won't work exactly :/. The code in this tutorial is a few years old now, so it's starting to show its age (but the explanations and philosophies we teach are still very good).

Cheers!

Reply
Shaun T. Avatar

Thanks for getting back to me Ryan, this is what I get:

Shauns-MBP:Development shaunthornburgh$ cd knpu-symfony-rest-example/
Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$ composer info "guzzlehttp/guzzle"
name : guzzlehttp/guzzle
descrip. : Guzzle is a PHP HTTP client library and framework for building RESTful web service clients
keywords : client, curl, framework, http, http client, rest, web service
versions : * 5.2.0
type : library
license : MIT License (MIT) (OSI approved) https://spdx.org/licenses/M...
source : [git] https://github.com/guzzle/g... 475b29ccd411f2fa8a408e64576418728c032cfa
dist : [zip] https://api.github.com/repo... 475b29ccd411f2fa8a408e64576418728c032cfa
names : guzzlehttp/guzzle

autoload
psr-4
GuzzleHttp\ => src/

requires
guzzlehttp/ringphp ~1.0
php >=5.4.0

requires (dev)
ext-curl *
phpunit/phpunit ~4.0
psr/log ~1.0
Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$ composer info "guzzle/guzzle"

[InvalidArgumentException]
Package guzzle/guzzle not found

show [--all] [-i|--installed] [-p|--platform] [-a|--available] [-s|--self] [-N|--name-only] [-P|--path] [-t|--tree] [-l|--latest] [-o|--outdated] [-m|--minor-only] [-D|--direct] [--strict] [-f|--format FORMAT] [--] [<package>] [<version>]

Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$

Reply

Hey Shaun T.!

Ah, perfect - then the situation shouldn't be too bad! Try this:


composer update guzzlehttp/guzzle

Even though this isn't in your composer.json, it's required by other libs, and you should be able to update it. Let me know if it works out!

Cheers!

Reply
Shaun T. Avatar
Shaun T. Avatar Shaun T. | weaverryan | posted 5 years ago | edited

Same again unfortunately :(


composer update guzzlehttp/guzzle
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Generating autoload files
> Incenteev\ParameterHandler\ScriptHandler::buildParameters
Updating the "app/config/parameters.yml" file
Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap declared at /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Composer/ScriptHandler.php accepts a Composer\Script\CommandEvent but post-update-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes in phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:316
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap
Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache declared at /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Composer/ScriptHandler.php accepts a Composer\Script\CommandEvent but post-update-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes in phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:316
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache
Clearing the cache for the dev environment with debug true
Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installAssets declared at /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Composer/ScriptHandler.php accepts a Composer\Script\CommandEvent but post-update-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes in phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:316
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installAssets
Trying to install assets as symbolic links.
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
The assets were installed using symbolic links.
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution
The assets were installed using symbolic links.
Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installRequirementsFile declared at /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Composer/ScriptHandler.php accepts a Composer\Script\CommandEvent but post-update-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes in phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:316
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::installRequirementsFile
Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::removeSymfonyStandardFiles declared at /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Composer/ScriptHandler.php accepts a Composer\Script\CommandEvent but post-update-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes in phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:316
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::removeSymfonyStandardFiles
Deprecation Notice: The callback Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::prepareDeploymentTarget declared at /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Composer/ScriptHandler.php accepts a Composer\Script\CommandEvent but post-update-cmd events use a Composer\Script\Event instance. Please adjust your type hint accordingly, see https://getcomposer.org/doc/articles/scripts.md#event-classes in phar:///usr/local/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php:316
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::prepareDeploymentTarget
Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$ php testing.php

Fatal error: Cannot use lexical variable $eventName as a parameter name in /Users/shaunthornburgh/Documents/Development/knpu-symfony-rest-example/vendor/guzzlehttp/guzzle/src/Event/Emitter.php on line 48
Shauns-MBP:knpu-symfony-rest-example shaunthornburgh$
Reply

Hey Shaun,

Hm, first of all I wonder what PHP version do you use? Execute "php -v" to see.

OK, that's a bit weird, but I'm starting to get lost here. Let me to summarize all we have and formulate a few steps for you:

1. Let's obviously require "guzzlehttp/guzzle" if it can't be found by Composer to update. Since you're on Guzzle 5.2.0, let's avoid BC breaks and require "^5.3":
composer require "guzzlehttp/guzzle:^5.3"

2. Composer should install the latest 5.3.1 version of Guzzle lib. To double check, run:
composer info guzzlehttp/guzzle

IN the output you should see "versions : * 5.3.1" which means you're on the latest available version of Guzzle in 5.x branch for now.

Then when you run "php testing.php" that "Fatal error: Cannot use lexical variable $eventName..." should be gone. If no, let us know, then you probably should upgrade to the latest version of Guzzle in 6.x branch or use a different PHP version.

Cheers!

Reply
Default user avatar
Default user avatar Vlad Catalin | Victor | posted 5 years ago

This worked for me!
Thanks for your answer!

Reply
Paweł C. Avatar
Paweł C. Avatar Paweł C. | Victor | posted 5 years ago | edited

I had same issue as Shaun
and command:

composer require "guzzlehttp/guzzle:^5.3"```

throws:

Problem 1

- Installation request for guzzlehttp/ringphp (locked at 1.0.7) -> satisfiab                                                                                                                                                             le by guzzlehttp/ringphp[1.0.7].
- guzzlehttp/guzzle 5.3.0 requires guzzlehttp/ringphp ^1.1 -> satisfiable by                                                                                                                                                              guzzlehttp/ringphp[1.1.0].
- guzzlehttp/guzzle 5.3.1 requires guzzlehttp/ringphp ^1.1 -> satisfiable by                                                                                                                                                              guzzlehttp/ringphp[1.1.0].
- guzzlehttp/guzzle 5.3.2 requires guzzlehttp/ringphp ^1.1 -> satisfiable by                                                                                                                                                              guzzlehttp/ringphp[1.1.0].
- Conclusion: don't install guzzlehttp/ringphp 1.1.0
- Installation request for guzzlehttp/guzzle ^5.3 -> satisfiable by guzzleht                                                                                                                                                             tp/guzzle[5.3.0, 5.3.1, 5.3.2].```

so I did:

composer require "guzzlehttp/ringphp:^1.1"```

and then:

composer require "guzzlehttp/guzzle:^5.3"`

and it works.

Reply

Hey Pawel,

Thanks for sharing your solution with others! Yeah, looks like you needed to upgrade "guzzlehttp/ringphp" to v1.1.x at least since you have only 1.0.7. Nice error message from Composer btw!

Cheers!

Reply

I gave up on the previous tutorial on REST here using Silex because the tutorial is ancient and it felt like I was running into a lot of compatibility issues due to the project being so old. I ended up finding another tutorial elsewhere and then coming back here for the next version of REST.

The trouble is now I seem to be running into the same problems here. When I googled a problem I was having with set up today, I found the following answer on stack overflow.

"The older version of Annotations is referring to the opcache.load_comments setting in php.ini, which does not exist in PHP 7:"

Isn't there a way to set up a virtual env that can be easily cloned so everyone is starting in the same place? If not, maybe tutorials should be pulled down after they reach a certain age.

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses a deprecated micro-framework called Silex. The fundamentals of REST are still ? valid, but the code we use can't be used in a real application.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "silex/silex": "~1.0", // v1.3.2
        "symfony/twig-bridge": "~2.1", // v2.7.3
        "symfony/security": "~2.4", // v2.7.3
        "doctrine/dbal": "^2.5.4", // v2.5.4
        "monolog/monolog": "~1.7.0", // 1.7.0
        "symfony/validator": "~2.4", // v2.7.3
        "symfony/expression-language": "~2.4" // v2.7.3
    },
    "require-dev": {
        "behat/mink": "~1.5", // v1.5.0
        "behat/mink-goutte-driver": "~1.0.9", // v1.0.9
        "behat/mink-selenium2-driver": "~1.1.1", // v1.1.1
        "behat/behat": "~2.5", // v2.5.5
        "behat/mink-extension": "~1.2.0", // v1.2.0
        "phpunit/phpunit": "~5.7.0", // 5.7.27
        "guzzle/guzzle": "~3.7" // v3.9.3
    }
}
userVoice