gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Alright, remember this hardcoded quote? Let's create a new class that can replace this with a random Samuel L Jackson quote instead.
In AppBundle
I'll create a new directory called Service
. Inside of our new Service
directory let's add a php class called QuoteGenerator
, and look how nicely it added that namespace for us!
namespace AppBundle\Service; | |
class QuoteGenerator | |
{ | |
... lines 7 - 20 | |
} |
Let's get to work by adding public function getRandomQuote()
. I'll paste in some quotes, then we can use $key = array_rand($quotes);
to get one of those quotes and return it:
... lines 1 - 4 | |
class QuoteGenerator | |
{ | |
public function getRandomQuote() | |
{ | |
$quotes = array( | |
'If my answers frighten you then you should cease asking scary questions. (Pulp Fiction)', | |
'Now that we know who you are, I know who I am. (Unbreakable)', | |
'Enough is enough! I have had it with these m*****f*****g snakes on this m*****f*****g plane! (Snakes on a Plane)', | |
'Say "what" again. SAY "WHAT" AGAIN! I dare you, I double dare you (Pulp Fiction)', | |
); | |
$key = array_rand($quotes); | |
$quote = $quotes[$key]; | |
return $quote; | |
} | |
} |
Next, I want to register this as a service and use it inside of my controller. So hit Shift
+Command
+O
, search for services.yml
, delete the comments under the services key, and put our service name there instead. I'll give it a nickname of quote_generator
:
... lines 1 - 5 | |
services: | |
quote_generator: | |
... lines 8 - 10 |
Tip
If you're using Symfony 3.3, your app/config/services.yml
contains some extra code
that may break things when following this tutorial! To keep things working - and learn
about what this code does - see https://knpuniversity.com/symfony-3.3-changes
Notice that PHPStorm is autocompleting my tabs wrong, I want to hit tab and have it give me four spaces. So let's fix that real quick in preferences by first hitting command+,
, then searching for "tab". In the left tree find yml under "Code Style" and update the indent from 2 to 4. Click apply, then ok and that should do it!
Yep, that looks perfect. As I was saying: we'll call the service, quote_generator
, but this name really doesn't matter. And of course we need the class
key, and we have autocomplete here too. If you hit Control
+Space
you'll get a list of all the different keys you can use to determine how a service is created, which is pretty incredible.
So we'll do class
, but don't type the whole long name! Like everywhere else, just type the last part of the class: here Quote
and hit tab to get the full line. Now add an empty arguments
line: we don't have any of those yet:
... lines 1 - 5 | |
services: | |
quote_generator: | |
class: AppBundle\Service\QuoteGenerator | |
arguments: [] |
This is now ready to be used in MovieController
.
Use Command
+Shift
+]
to move over to that tab. And here instead of this quote, we'll say $this->get('')
and the plugin is already smart enough to know that the quote_generator
service is there. And it even knows that there is a method on it called getRandomQuote()
:
... lines 1 - 10 | |
class MovieController extends BaseController | |
{ | |
... lines 13 - 15 | |
public function newAction(Request $request) | |
{ | |
... lines 18 - 33 | |
return $this->render('movie/new.html.twig', array( | |
'quote' => $this->get('quote_generator')->getRandomQuote(), | |
... line 36 | |
)); | |
} | |
... lines 39 - 52 | |
} |
This is one my favorite features of the Symfony plugin.
Save that, head back to the form, refresh and now we see a new random quote at the bottom of the page.
Now in QuoteGenerator
, let's pretend like we need access to some service - like maybe we want to log something inside of here. The normal way of doing that is with dependency injection, where we pass the logger through via the constructor
. So let's do exactly that, but with as little work as possible.
I could type public function __construct
, but instead I'm going to use the generate command. Hit Command
+N
and pick the "Constructor" option from the menu here. I don't think this constructor comment is all that helpful, so go back into preferences with Command
+,
, search for "templates", and under "file and code templates", we have one called "PHP Constructors". I'll just go in here and delete the comment from the template.
Ok, let's try adding the constructor again. Much cleaner:
... lines 1 - 4 | |
class QuoteGenerator | |
{ | |
public function __construct() | |
{ | |
} | |
... lines 11 - 25 | |
} |
At this point we need the logger, so add the argument LoggerInterface $logger
:
... lines 1 - 4 | |
use Psr\Log\LoggerInterface; | |
class QuoteGenerator | |
{ | |
... lines 9 - 14 | |
public function __construct(LoggerInterface $logger) | |
{ | |
$this->logger = $logger; | |
} | |
... lines 19 - 34 | |
} |
This is the point where we would normally create the private $logger
property above, and set it down in the constructor with $this->logger = $logger;
. This is a really common task, so if we can find a faster way to do this that would be awesome.
Time to go back to the actions shortcut, Option
+Enter
, select "Initialize fields", then choose logger
, and it adds all that code for you:
... lines 1 - 6 | |
class QuoteGenerator | |
{ | |
/** | |
* @var LoggerInterface | |
*/ | |
private $logger; | |
public function __construct(LoggerInterface $logger) | |
{ | |
$this->logger = $logger; | |
} | |
... lines 19 - 34 | |
} |
We don't even have to feed it!
Farther down, it's really easy to use, $this->logger->info('Selected quote: '.$quote);
:
... lines 1 - 6 | |
class QuoteGenerator | |
{ | |
... lines 9 - 19 | |
public function getRandomQuote() | |
{ | |
... lines 22 - 29 | |
$quote = $quotes[$key]; | |
$this->logger->info('Selected quote: '.$quote); | |
... lines 32 - 33 | |
} | |
} |
We've added the argument here, so now we need to go to services.yml
, which I'll move over to. And notice it's highlighting quote_generator
with a missing argument message because it knows that this service has one argument. So we can say @logger
, or even Command
+O
and then use autocomplete to help us:
... lines 1 - 5 | |
services: | |
quote_generator: | |
class: AppBundle\Service\QuoteGenerator | |
arguments: ['@logger'] |
Head back, refresh, it still works and I could go down here to click into my profiler to check out the logs. Or, in PhpStorm, we can go to the bottom right Symfony menu, click it and use the shortcut to get into the Profiler. Click that, go to logs, and there's our quote right there.
The autocompletion of the services and the ability to generate your properties is probably one of the most important features that you need to master with PHPStorm because it's going to help you fly when you develop in Symfony.
Hey Yahya E.!
No worries - it's totally fine to ask whatever questions you have :). About the error, I would check your services.yml file: https://knpuniversity.com/screencast/phpstorm/service-shortcuts#registering-a-service. Very simply, if you add the right code there, then you WILL have a quote_generator service. So, somehow, something is going wrong. Oh, and I just realized that your error is showing up in the prod environment! So, if you're using the prod environment, make sure to clear your cache first!
bin/console cache:clear --env=prod
And about the deprecation, yep, pretty self-explanatory - there was a change made in the core of Symfony that will (in the future) require you to say if ($form->isSubmitted() && $form->isValid()) {
instead of calling only isValid().
Cheers!
which plugin should I use in phpstorm to have class name auto-completion in services.yml like shown in video?
Hey vikbert
The main plugin you should install and activate is "Symfony plugin", then you can install a few more like "Twig support", "PHP Annotations", "PHP Toolbox"
Oh, and we have a dedicated tutorial about developing using PhpStorm, you may learn a lot of tricks ;)
https://knpuniversity.com/s...
Cheers!
If you are using Symfony 3 and getting "ServiceNotFoundException"
Add public: ture under app/config/service.yml file, so it looks like this
services:
quote_generator:
class: AppBundle\Service\QuoteGenerator
arguments: []
public: true
Hey Yan, thanks for sharing it! I suppose you mean exactly Symfony 3.3, which with its default configuration makes all services private unless you override some of them if needed.
Cheers!
// composer.json
{
"require": {
"php": ">=5.3.9, <7.3.0",
"symfony/symfony": "2.8.*", // v2.8.15
"doctrine/orm": "^2.4.8", // v2.4.8
"doctrine/dbal": "<2.5", // v2.4.5
"doctrine/doctrine-bundle": "~1.4", // 1.6.4
"symfony/assetic-bundle": "~2.3", // v2.8.1
"symfony/swiftmailer-bundle": "~2.3,>=2.3.10", // v2.4.2
"symfony/monolog-bundle": "^3.0.2", // v3.0.2
"sensio/distribution-bundle": "~5.0", // v5.0.17
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.18
"incenteev/composer-parameter-handler": "~2.0" // v2.1.2
},
"require-dev": {
"sensio/generator-bundle": "~3.0", // v3.1.2
"symfony/phpunit-bridge": "~2.7" // v2.8.15
}
}
Thanks for the great tutorial.
I am using Symfony3 and getting this error for quote_generator service. I know Symfony3 is not the topic for this course but still any help is appreciated.
[2017-01-16 23:41:40] request.CRITICAL: Uncaught PHP Exception Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: "You have requested a non-existent service "quote_generator"." at /home/vagrant/Code/phpStorm/var/cache/prod/classes.php line 3461 {"exception":"[object] (Symfony\\Component\\DependencyInjection\\Exception\\ServiceNotFoundException(code: 0): You have requested a non-existent service \"quote_generator\". at /home/vagrant/Code/phpStorm/var/cache/prod/classes.php:3461)"} []
Meanwhile for other users, there is also an error for form:
[2017-01-16 23:41:40] php.INFO: User Deprecated: Call Form::isValid() with an unsubmitted form is deprecated since version 3.2 and will throw an exception in 4.0. Use Form::isSubmitted() before Form::isValid() instead. {"exception":"[object] (ErrorException(code: 0): User Deprecated: Call Form::isValid() with an unsubmitted form is deprecated since version 3.2 and will throw an exception in 4.0. Use Form::isSubmitted() before Form::isValid() instead. at /home/vagrant/Code/phpStorm/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php:727)"} []
This one seems self-explanatory.
Thanks