gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Let's make this date dynamic! The field on Question
that we're going to use is $askedAt
, which - remember - might be null. If a Question
hasn't been published yet, then it won't have an askedAt
.
Let's plan for this. In the template, add {% if question.askedAt %}
with an {% else %}
and {% endif %}
... lines 1 - 5 | |
<div class="container"> | |
<div class="row"> | |
<div class="col-12"> | |
<h2 class="my-4">Question:</h2> | |
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);"> | |
<div class="q-container-show p-4"> | |
<div class="row"> | |
<div class="col-2 text-center"> | |
<img src="{{ asset('images/tisha.png') }}" width="100" height="100" alt="Tisha avatar"> | |
<div class="mt-3"> | |
<small> | |
{% if question.askedAt %} | |
... lines 18 - 19 | |
{% else %} | |
... line 21 | |
{% endif %} | |
</small> | |
... lines 24 - 29 | |
</div> | |
</div> | |
... lines 32 - 39 | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
... lines 45 - 72 | |
</div> | |
... lines 74 - 75 |
If the question is not published, say (unpublished)
.
... lines 1 - 5 | |
<div class="container"> | |
<div class="row"> | |
<div class="col-12"> | |
<h2 class="my-4">Question:</h2> | |
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);"> | |
<div class="q-container-show p-4"> | |
<div class="row"> | |
<div class="col-2 text-center"> | |
<img src="{{ asset('images/tisha.png') }}" width="100" height="100" alt="Tisha avatar"> | |
<div class="mt-3"> | |
<small> | |
{% if question.askedAt %} | |
... lines 18 - 19 | |
{% else %} | |
(unpublished) | |
{% endif %} | |
</small> | |
... lines 24 - 29 | |
</div> | |
</div> | |
... lines 32 - 39 | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
... lines 45 - 72 | |
</div> | |
... lines 74 - 75 |
In a real app, we would probably not allow users to see unpublished questions... we could do that in our controller by checking for this field and saying throw $this->createNotFoundException()
if it's null. But... maybe a user will be able to preview their own unpublished questions. If they did, we'll show unpublished
.
The easiest way to try to print the date would be to say {{ question.askedAt }}
.
... lines 1 - 5 | |
<div class="container"> | |
<div class="row"> | |
<div class="col-12"> | |
<h2 class="my-4">Question:</h2> | |
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);"> | |
<div class="q-container-show p-4"> | |
<div class="row"> | |
<div class="col-2 text-center"> | |
<img src="{{ asset('images/tisha.png') }}" width="100" height="100" alt="Tisha avatar"> | |
<div class="mt-3"> | |
<small> | |
{% if question.askedAt %} | |
... line 18 | |
{{ question.askedAt }} | |
{% else %} | |
(unpublished) | |
{% endif %} | |
</small> | |
... lines 24 - 29 | |
</div> | |
</div> | |
... lines 32 - 39 | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
... lines 45 - 72 | |
</div> | |
... lines 74 - 75 |
But... you might be shouting: "Hey Ryan! That's not going to work!".
And... you're right:
Object of class
DateTime
could not be converted to string
We know that when we have a datetime
type in Doctrine, it's stored in PHP as a DateTime
object. That's nice because DateTime
objects are easy to work with... but we can't simply print them.
To fix this, pass the DateTime
object through a |date()
filter. This takes a format argument - something like Y-m-d H:i:s
.
... lines 1 - 5 | |
<div class="container"> | |
<div class="row"> | |
<div class="col-12"> | |
<h2 class="my-4">Question:</h2> | |
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);"> | |
<div class="q-container-show p-4"> | |
<div class="row"> | |
<div class="col-2 text-center"> | |
<img src="{{ asset('images/tisha.png') }}" width="100" height="100" alt="Tisha avatar"> | |
<div class="mt-3"> | |
<small> | |
{% if question.askedAt %} | |
... line 18 | |
{{ question.askedAt|date('Y-m-d H:i:s') }} | |
{% else %} | |
(unpublished) | |
{% endif %} | |
</small> | |
... lines 24 - 29 | |
</div> | |
</div> | |
... lines 32 - 39 | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
... lines 45 - 72 | |
</div> | |
... lines 74 - 75 |
When we try the page now... it's technically correct... but yikes! This... well... how can I put this politely: it looks like a backend developer designed this.
Whenever I render dates, I like to make them relative. Instead of printing an exact date, I prefer something like "10 minutes ago". It also avoids timezone problems... because 10 minutes ago makes sense to everyone! But this exact date would really need a timezone to make sense.
So let's do this. Start by adding the word "Asked" back before the date. Cool.
... lines 1 - 5 | |
<div class="container"> | |
<div class="row"> | |
<div class="col-12"> | |
<h2 class="my-4">Question:</h2> | |
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);"> | |
<div class="q-container-show p-4"> | |
<div class="row"> | |
<div class="col-2 text-center"> | |
<img src="{{ asset('images/tisha.png') }}" width="100" height="100" alt="Tisha avatar"> | |
<div class="mt-3"> | |
<small> | |
{% if question.askedAt %} | |
Asked <br> | |
{{ question.askedAt|date('Y-m-d H:i:s') }} | |
{% else %} | |
(unpublished) | |
{% endif %} | |
</small> | |
... lines 24 - 29 | |
</div> | |
</div> | |
... lines 32 - 39 | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
... lines 45 - 72 | |
</div> | |
... lines 74 - 75 |
To convert the DateTime
into a friendly string, we can install a nice bundle. At your terminal, run:
composer require "knplabs/knp-time-bundle:1.19.0"
You could find this bundle if you googled for "Symfony ago". As we know, the main thing that a bundle gives us is more services. In this case, the bundle gives us one main service that provides a Twig filter called ago
.
It's pretty awesome. Back in the template, add |ago
.
... lines 1 - 5 | |
<div class="container"> | |
<div class="row"> | |
<div class="col-12"> | |
<h2 class="my-4">Question:</h2> | |
<div style="box-shadow: 2px 3px 9px 4px rgba(0,0,0,0.04);"> | |
<div class="q-container-show p-4"> | |
<div class="row"> | |
<div class="col-2 text-center"> | |
<img src="{{ asset('images/tisha.png') }}" width="100" height="100" alt="Tisha avatar"> | |
<div class="mt-3"> | |
<small> | |
{% if question.askedAt %} | |
Asked <br> | |
{{ question.askedAt|ago }} | |
{% else %} | |
(unpublished) | |
{% endif %} | |
</small> | |
... lines 24 - 29 | |
</div> | |
</div> | |
... lines 32 - 39 | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
... lines 45 - 72 | |
</div> | |
... lines 74 - 75 |
We're done! When we refresh now... woohoo!
Asked 1 month ago
Next: let's make the homepage dynamic by querying for all of the questions in the database and rendering them. Along the way, we're going to learn a secret about the repository object.
Hey Szymon,
Did you download the course code and started from start/ folder? Did you follow all the instructions from the README.md file there?
Cheers!
Hey Ccc123,
Looks like you're using a newer version of dependencies in your project. Did you download the course code and started from the start/ directory? Or you started with a fresh new Symfony application? If you started with our course code, try to install the same version of the bundle like we use in our videos, for this run:
composer require "knplabs/knp-time-bundle:v1.16.0"
Let me know if it does not help. Otherwise, I would like to know more about your Symfony version so I could help further.
Cheers!
Hi Victor,
Yeah I downloaded the course code before I started. I just tried installing the version that was in the final/ directory's composer.json and it worked! Thank you.
Hey Ruslan,
What do you mean about "auto fill"? Something like PhpStorm live templates? If so - here's related screencast about it: https://symfonycasts.com/sc... . Otherwise, you're most probably talking about Symfony Plugin that auto completes a lot of useful things in PhpStorm. You can find more info on how to install and enable this plugin here: https://symfonycasts.com/sc...
I hope this helps!
Cheers!
// composer.json
{
"require": {
"php": "^7.4.1",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/doctrine-bundle": "^2.1", // 2.1.1
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.0.2
"doctrine/orm": "^2.7", // 2.8.2
"knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
"knplabs/knp-time-bundle": "^1.11", // v1.16.0
"sensio/framework-extra-bundle": "^6.0", // v6.2.1
"sentry/sentry-symfony": "^4.0", // 4.0.3
"stof/doctrine-extensions-bundle": "^1.4", // v1.5.0
"symfony/asset": "5.1.*", // v5.1.2
"symfony/console": "5.1.*", // v5.1.2
"symfony/dotenv": "5.1.*", // v5.1.2
"symfony/flex": "^1.3.1", // v1.17.5
"symfony/framework-bundle": "5.1.*", // v5.1.2
"symfony/monolog-bundle": "^3.0", // v3.5.0
"symfony/stopwatch": "5.1.*", // v5.1.2
"symfony/twig-bundle": "5.1.*", // v5.1.2
"symfony/webpack-encore-bundle": "^1.7", // v1.8.0
"symfony/yaml": "5.1.*", // v5.1.2
"twig/extra-bundle": "^2.12|^3.0", // v3.0.4
"twig/twig": "^2.12|^3.0" // v3.0.4
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.0
"symfony/debug-bundle": "5.1.*", // v5.1.2
"symfony/maker-bundle": "^1.15", // v1.23.0
"symfony/var-dumper": "5.1.*", // v5.1.2
"symfony/web-profiler-bundle": "5.1.*", // v5.1.2
"zenstruck/foundry": "^1.1" // v1.5.0
}
}
After installing new bundle Knp Time (same version like in video), following error has occur:
Attempted to load class "Locale" from the global namespace.<br />Did you forget a "use" statement?
I tried
use Knp\Bundle\TimeBundle\Templating\Helper\TimeHelper;
but it doesn't help.What could throw this error?