21 | */
22 | class Validator
23 | {
24 | public function validateUsername(?string $username): string
25 | {
26 | if (empty($username)) {
27 | throw new InvalidArgumentException('The username can not be empty.');
28 | }
29 |
30 | if (1 !== preg_match('/^[a-z_]+$/', $username)) {
31 | throw new InvalidArgumentException('The username must contain only lowercase latin characters and underscores.');
32 | }
33 |
34 | return $username;
35 | }
36 |
37 | public function validatePassword(?string $plainPassword): string
38 | {
39 | if (empty($plainPassword)) {
40 | throw new InvalidArgumentException('The password can not be empty.');
41 | }
42 |
43 | if (mb_strlen(trim($plainPassword)) < 6) {
44 | throw new InvalidArgumentException('The password must be at least 6 characters long.');
45 | }
46 |
47 | return $plainPassword;
48 | }
49 |
50 | public function validateEmail(?string $email): string
51 | {
52 | if (empty($email)) {
53 | throw new InvalidArgumentException('The email can not be empty.');
54 | }
55 |
56 | if (false === mb_strpos($email, '@')) {
57 | throw new InvalidArgumentException('The email should look like a real email.');
58 | }
59 |
60 | return $email;
61 | }
62 |
63 | public function validateFullName(?string $fullName): string
64 | {
65 | if (empty($fullName)) {
66 | throw new InvalidArgumentException('The full name can not be empty.');
67 | }
68 |
69 | return $fullName;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/templates/admin/blog/_delete_form.html.twig:
--------------------------------------------------------------------------------
1 | {{ include('blog/_delete_post_confirmation.html.twig') }}
2 |
9 |
--------------------------------------------------------------------------------
/templates/admin/blog/_form.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | By default, forms enable client-side validation. This means that you can't
3 | test the server-side validation errors from the browser. To temporarily
4 | disable this validation, add the 'novalidate' attribute:
5 |
6 | {{ form_start(form, {attr: {novalidate: 'novalidate'}}) }}
7 | #}
8 |
9 | {% if show_confirmation|default(false) %}
10 | {% set attr = {'data-confirmation': 'true'} %}
11 | {{ include('blog/_delete_post_confirmation.html.twig') }}
12 | {% endif %}
13 |
14 | {{ form_start(form, {attr: attr|default({})}) }}
15 | {{ form_widget(form) }}
16 |
17 |
18 | {{ button_label|default('label.create_post'|trans) }}
19 |
20 |
21 | {% if include_back_to_home_link|default(false) %}
22 |
23 | {{ 'action.back_to_list'|trans }}
24 |
25 | {% endif %}
26 | {{ form_end(form) }}
27 |
--------------------------------------------------------------------------------
/templates/admin/blog/edit.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'admin/layout.html.twig' %}
2 |
3 | {% block body_id 'admin_post_edit' %}
4 |
5 | {% block main %}
6 | {{ 'title.edit_post'|trans({'%id%': post.id}) }}
7 |
8 | {{ include('admin/blog/_form.html.twig', {
9 | form: form,
10 | button_label: 'action.save'|trans,
11 | include_back_to_home_link: true,
12 | }, with_context = false) }}
13 | {% endblock %}
14 |
15 | {% block sidebar %}
16 |
21 |
22 |
23 | {{ include('admin/blog/_delete_form.html.twig', {post: post}, with_context = false) }}
24 |
25 |
26 | {{ parent() }}
27 |
28 | {{ show_source_code(_self) }}
29 | {% endblock %}
30 |
--------------------------------------------------------------------------------
/templates/admin/blog/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'admin/layout.html.twig' %}
2 |
3 | {% block body_id 'admin_post_index' %}
4 |
5 | {% block main %}
6 | {{ 'title.post_list'|trans }}
7 |
8 |
9 |
10 |
11 | {{ 'label.title'|trans }}
12 | {{ 'label.published_at'|trans }}
13 | {{ 'label.actions'|trans }}
14 |
15 |
16 |
17 | {% for post in posts %}
18 |
19 | {{ post.title }}
20 | {# it's not mandatory to set the timezone in localizeddate(). This is done to
21 | avoid errors when the 'intl' PHP extension is not available and the application
22 | is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
23 | {{ post.publishedAt|localizeddate('medium', 'short', null, 'UTC') }}
24 |
25 |
34 |
35 |
36 | {% else %}
37 |
38 | {{ 'post.no_posts_found'|trans }}
39 |
40 | {% endfor %}
41 |
42 |
43 | {% endblock %}
44 |
45 | {% block sidebar %}
46 |
51 |
52 | {{ parent() }}
53 |
54 | {{ show_source_code(_self) }}
55 | {% endblock %}
56 |
--------------------------------------------------------------------------------
/templates/admin/blog/new.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'admin/layout.html.twig' %}
2 |
3 | {% block body_id 'admin_post_new' %}
4 |
5 | {% block main %}
6 | {{ 'title.post_new'|trans }}
7 |
8 | {{ form_start(form) }}
9 | {{ form_row(form.title) }}
10 | {{ form_row(form.summary) }}
11 | {{ form_row(form.content) }}
12 | {{ form_row(form.publishedAt) }}
13 | {{ form_row(form.tags) }}
14 |
15 |
16 | {{ 'label.create_post'|trans }}
17 |
18 | {{ form_widget(form.saveAndCreateNew, {label: 'label.save_and_create_new', attr: {class: 'btn btn-primary'}}) }}
19 |
20 | {{ 'action.back_to_list'|trans }}
21 |
22 | {{ form_end(form) }}
23 | {% endblock %}
24 |
25 | {% block sidebar %}
26 | {{ parent() }}
27 |
28 | {{ show_source_code(_self) }}
29 | {% endblock %}
30 |
--------------------------------------------------------------------------------
/templates/admin/blog/show.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'admin/layout.html.twig' %}
2 |
3 | {% block body_id 'admin_post_show' %}
4 |
5 | {% block main %}
6 | {{ post.title }}
7 |
8 |
9 | {{ post.publishedAt|localizeddate('long', 'medium', null, 'UTC') }}
10 | {{ post.author.fullName }}
11 |
12 |
13 |
14 |
{{ 'label.summary'|trans }} : {{ post.summary }}
15 |
16 |
17 | {{ post.content|md2html }}
18 |
19 | {{ include('blog/_post_tags.html.twig') }}
20 | {% endblock %}
21 |
22 | {% block sidebar %}
23 |
28 |
29 |
30 | {{ include('admin/blog/_delete_form.html.twig', {post: post}, with_context = false) }}
31 |
32 |
33 | {{ parent() }}
34 |
35 | {{ show_source_code(_self) }}
36 | {% endblock %}
37 |
--------------------------------------------------------------------------------
/templates/admin/layout.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | This is the base template of the all backend pages. Since this layout is similar
3 | to the global layout, we inherit from it to just change the contents of some
4 | blocks. In practice, backend templates are using a three-level inheritance,
5 | showing how powerful, yet easy to use, is Twig's inheritance mechanism.
6 | See https://symfony.com/doc/current/book/templating.html#template-inheritance-and-layouts
7 | #}
8 | {% extends 'base.html.twig' %}
9 |
10 | {% block stylesheets %}
11 | {{ parent() }}
12 | {{ encore_entry_link_tags('admin') }}
13 | {% endblock %}
14 |
15 | {% block javascripts %}
16 | {{ parent() }}
17 | {{ encore_entry_script_tags('admin') }}
18 | {% endblock %}
19 |
20 | {% block header_navigation_links %}
21 |
22 |
23 | {{ 'menu.post_list'|trans }}
24 |
25 |
26 |
27 |
28 | {{ 'menu.back_to_blog'|trans }}
29 |
30 |
31 | {% endblock %}
32 |
--------------------------------------------------------------------------------
/templates/blog/_comment_form.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | By default, forms enable client-side validation. This means that you can't
3 | test the server-side validation errors from the browser. To temporarily
4 | disable this validation, add the 'novalidate' attribute:
5 |
6 | {{ form_start(form, {method: ..., action: ..., attr: {novalidate: 'novalidate'}}) }}
7 | #}
8 |
9 | {{ form_start(form, {method: 'POST', action: path('comment_new', {'postSlug': post.slug})}) }}
10 | {# instead of displaying form fields one by one, you can also display them
11 | all with their default options and styles just by calling to this function:
12 |
13 | {{ form_widget(form) }}
14 | #}
15 |
16 |
17 |
18 | {{ 'title.add_comment'|trans }}
19 |
20 |
21 | {# Render any global form error (e.g. when a constraint on a public getter method failed) #}
22 | {{ form_errors(form) }}
23 |
24 |
25 | {{ form_label(form.content, 'label.content', {label_attr: {class: 'hidden'}}) }}
26 |
27 | {# Render any errors for the "content" field (e.g. when a class property constraint failed) #}
28 | {{ form_errors(form.content) }}
29 |
30 | {{ form_widget(form.content, {attr: {rows: 10}}) }}
31 | {{ form_help(form.content) }}
32 |
33 |
34 |
35 |
36 | {{ 'action.publish_comment'|trans }}
37 |
38 |
39 |
40 | {{ form_end(form) }}
41 |
--------------------------------------------------------------------------------
/templates/blog/_delete_post_confirmation.html.twig:
--------------------------------------------------------------------------------
1 | {# Bootstrap modal, see http://getbootstrap.com/javascript/#modals #}
2 |
3 |
4 |
5 |
6 |
{{ 'delete_post_modal.title'|trans }}
7 |
{{ 'delete_post_modal.body'|trans }}
8 |
9 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/templates/blog/_post_tags.html.twig:
--------------------------------------------------------------------------------
1 | {% if not post.tags.empty %}
2 |
3 | {% for tag in post.tags %}
4 |
7 | {{ tag.name }}
8 |
9 | {% endfor %}
10 |
11 | {% endif %}
12 |
13 |
--------------------------------------------------------------------------------
/templates/blog/_rss.html.twig:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/templates/blog/about.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ 'help.app_description'|trans|raw }}
5 |
6 |
7 | {{ 'help.more_information'|trans|raw }}
8 |
9 |
10 |
11 |
12 | {# it's not mandatory to set the timezone in localizeddate(). This is done to
13 | avoid errors when the 'intl' PHP extension is not available and the application
14 | is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
15 |
16 |
--------------------------------------------------------------------------------
/templates/blog/comment_form_error.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block body_id 'comment_form_error' %}
4 |
5 | {% block main %}
6 | {{ 'title.comment_error'|trans }}
7 |
8 |
9 | {{ include('blog/_comment_form.html.twig') }}
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/templates/blog/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block body_id 'blog_index' %}
4 |
5 | {% block main %}
6 | {% for post in paginator.results %}
7 |
8 |
13 |
14 |
15 | {{ post.publishedAt|localizeddate('long', 'medium', null, 'UTC') }}
16 | {{ post.author.fullName }}
17 |
18 |
19 | {{ post.summary }}
20 |
21 | {{ include('blog/_post_tags.html.twig') }}
22 |
23 | {% else %}
24 | {{ 'post.no_posts_found'|trans }}
25 | {% endfor %}
26 |
27 | {% if paginator.hasToPaginate %}
28 |
29 |
50 |
51 | {% endif %}
52 | {% endblock %}
53 |
54 | {% block sidebar %}
55 | {{ parent() }}
56 |
57 | {{ show_source_code(_self) }}
58 | {{ include('blog/_rss.html.twig') }}
59 | {% endblock %}
60 |
--------------------------------------------------------------------------------
/templates/blog/index.xml.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ 'rss.title'|trans }}
5 | {{ 'rss.description'|trans }}
6 | {{ 'now'|date('r', timezone='GMT') }}
7 | {{ (paginator.results|last).publishedAt|default('now')|date('r', timezone='GMT') }}
8 | {{ url('blog_index') }}
9 | {{ app.request.locale }}
10 |
11 | {% for post in paginator.results %}
12 | -
13 |
{{ post.title }}
14 | {{ post.summary }}
15 | {{ url('blog_post', {'slug': post.slug}) }}
16 | {{ url('blog_post', {'slug': post.slug}) }}
17 | {{ post.publishedAt|date(format='r', timezone='GMT') }}
18 | {{ post.author.email }}
19 | {% for tag in post.tags %}
20 | {{ tag.name }}
21 | {% endfor %}
22 |
23 | {% endfor %}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/templates/blog/post_show.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block body_id 'blog_post_show' %}
4 |
5 | {% block main %}
6 | {{ post.title }}
7 |
8 |
9 | {{ post.publishedAt|localizeddate('long', 'medium', null, 'UTC') }}
10 | {{ post.author.fullName }}
11 |
12 |
13 | {{ post.content|md2html }}
14 |
15 | {{ include('blog/_post_tags.html.twig') }}
16 |
17 |
35 |
36 |
37 | {{ 'post.num_comments'|trans({ 'count': post.comments|length }) }}
38 |
39 |
40 | {% for comment in post.comments %}
41 |
54 | {% else %}
55 |
58 | {% endfor %}
59 | {% endblock %}
60 |
61 | {% block sidebar %}
62 | {% if is_granted('edit', post) %}
63 |
68 | {% endif %}
69 |
70 | {# the parent() function includes the contents defined by the parent template
71 | ('base.html.twig') for this block ('sidebar'). This is a very convenient way
72 | to share common contents in different templates #}
73 | {{ parent() }}
74 |
75 | {{ show_source_code(_self) }}
76 | {{ include('blog/_rss.html.twig') }}
77 | {% endblock %}
78 |
--------------------------------------------------------------------------------
/templates/blog/search.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block javascripts %}
4 | {{ parent() }}
5 | {{ encore_entry_script_tags('search') }}
6 | {% endblock %}
7 |
8 | {% block body_id 'blog_search' %}
9 |
10 | {% block main %}
11 |
22 |
23 |
24 |
25 | {% endblock %}
26 |
27 | {% block sidebar %}
28 | {{ parent() }}
29 |
30 | {{ show_source_code(_self) }}
31 | {% endblock %}
32 |
--------------------------------------------------------------------------------
/templates/bundles/TwigBundle/Exception/error.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | This template is used to render any error different from 403, 404 and 500.
3 |
4 | This is the simplest way to customize error pages in Symfony applications.
5 | In case you need it, you can also hook into the internal exception handling
6 | made by Symfony. This allows you to perform advanced tasks and even recover
7 | your application from some errors.
8 | See https://symfony.com/doc/current/cookbook/controller/error_pages.html
9 | #}
10 |
11 | {% extends 'base.html.twig' %}
12 |
13 | {% block body_id 'error' %}
14 |
15 | {% block main %}
16 | {{ 'http_error.name'|trans({ '%status_code%': status_code }) }}
17 |
18 |
19 | {{ 'http_error.description'|trans({ '%status_code%': status_code }) }}
20 |
21 |
22 | {{ 'http_error.suggestion'|trans({ '%url%': path('blog_index') })|raw }}
23 |
24 | {% endblock %}
25 |
26 | {% block sidebar %}
27 | {{ parent() }}
28 |
29 | {{ show_source_code(_self) }}
30 | {% endblock %}
31 |
--------------------------------------------------------------------------------
/templates/bundles/TwigBundle/Exception/error403.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | This template is used to render errors of type HTTP 403 (Forbidden)
3 |
4 | This is the simplest way to customize error pages in Symfony applications.
5 | In case you need it, you can also hook into the internal exception handling
6 | made by Symfony. This allows you to perform advanced tasks and even recover
7 | your application from some errors.
8 | See https://symfony.com/doc/current/cookbook/controller/error_pages.html
9 | #}
10 |
11 | {% extends 'base.html.twig' %}
12 |
13 | {% block body_id 'error' %}
14 |
15 | {% block main %}
16 | {{ 'http_error.name'|trans({ '%status_code%': 403 }) }}
17 |
18 |
19 | {{ 'http_error_403.description'|trans }}
20 |
21 |
22 | {{ 'http_error_403.suggestion'|trans }}
23 |
24 | {% endblock %}
25 |
26 | {% block sidebar %}
27 | {{ parent() }}
28 |
29 | {{ show_source_code(_self) }}
30 | {% endblock %}
31 |
--------------------------------------------------------------------------------
/templates/bundles/TwigBundle/Exception/error404.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | This template is used to render errors of type HTTP 404 (Not Found)
3 |
4 | This is the simplest way to customize error pages in Symfony applications.
5 | In case you need it, you can also hook into the internal exception handling
6 | made by Symfony. This allows you to perform advanced tasks and even recover
7 | your application from some errors.
8 | See https://symfony.com/doc/current/cookbook/controller/error_pages.html
9 | #}
10 |
11 | {% extends 'base.html.twig' %}
12 |
13 | {% block body_id 'error' %}
14 |
15 | {% block main %}
16 | {{ 'http_error.name'|trans({ '%status_code%': 404 }) }}
17 |
18 |
19 | {{ 'http_error_404.description'|trans }}
20 |
21 |
22 | {{ 'http_error_404.suggestion'|trans({ '%url%': path('blog_index') })|raw }}
23 |
24 | {% endblock %}
25 |
26 | {% block sidebar %}
27 | {{ parent() }}
28 |
29 | {{ show_source_code(_self) }}
30 | {% endblock %}
31 |
--------------------------------------------------------------------------------
/templates/bundles/TwigBundle/Exception/error500.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | This template is used to render errors of type HTTP 500 (Internal Server Error)
3 |
4 | This is the simplest way to customize error pages in Symfony applications.
5 | In case you need it, you can also hook into the internal exception handling
6 | made by Symfony. This allows you to perform advanced tasks and even recover
7 | your application from some errors.
8 | See https://symfony.com/doc/current/cookbook/controller/error_pages.html
9 | #}
10 |
11 | {% extends 'base.html.twig' %}
12 |
13 | {% block stylesheets %}
14 | {{ parent() }}
15 |
16 | {% endblock %}
17 |
18 | {% block body_id 'error' %}
19 |
20 | {% block main %}
21 | {{ 'http_error.name'|trans({ '%status_code%': 500 }) }}
22 |
23 |
24 | {{ 'http_error_500.description'|trans }}
25 |
26 |
27 | {{ 'http_error_500.suggestion'|trans({ '%url%': path('blog_index') })|raw }}
28 |
29 | {% endblock %}
30 |
31 | {% block sidebar %}
32 | {{ parent() }}
33 |
34 | {{ show_source_code(_self) }}
35 | {% endblock %}
36 |
--------------------------------------------------------------------------------
/templates/debug/source_code.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ 'help.show_code'|trans|raw }}
4 |
5 |
6 |
7 | {{ 'action.show_code'|trans }}
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 | {% if controller %}
22 |
23 |
{{ controller.source_code }}
24 | {% else %}
25 |
26 |
{{ 'not_available'|trans }}
27 | {% endif %}
28 |
29 |
30 |
{{ template.source_code }}
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/templates/default/_flash_messages.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | This is a template fragment designed to be included in other templates
3 | See https://symfony.com/doc/current/book/templating.html#including-other-templates
4 |
5 | A common practice to better distinguish between templates and fragments is to
6 | prefix fragments with an underscore. That's why this template is called
7 | '_flash_messages.html.twig' instead of 'flash_messages.html.twig'
8 | #}
9 |
10 | {#
11 | The request method check is needed to prevent starting the session when looking for "flash messages":
12 | https://symfony.com/doc/current/session/avoid_session_start.html
13 |
14 | TIP: With FOSHttpCache you can also adapt this to make it cache safe:
15 | https://foshttpcachebundle.readthedocs.io/en/latest/features/helpers/flash-message.html
16 | #}
17 | {% if app.request.hasPreviousSession %}
18 |
19 | {% for type, messages in app.flashes %}
20 | {% for message in messages %}
21 | {# Bootstrap alert, see http://getbootstrap.com/components/#alerts #}
22 |
23 |
24 | ×
25 |
26 |
27 | {{ message|trans }}
28 |
29 | {% endfor %}
30 | {% endfor %}
31 |
32 | {% endif %}
33 |
--------------------------------------------------------------------------------
/templates/default/homepage.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block body_id 'homepage' %}
4 |
5 | {#
6 | the homepage is a special page which displays neither a header nor a footer.
7 | this is done with the 'trick' of defining empty Twig blocks without any content
8 | #}
9 | {% block header %}{% endblock %}
10 | {% block footer %}{% endblock %}
11 |
12 | {% block body %}
13 |
16 |
17 |
44 | {% endblock %}
45 |
--------------------------------------------------------------------------------
/templates/form/fields.html.twig:
--------------------------------------------------------------------------------
1 | {#
2 | Each field type is rendered by a template fragment, which is determined
3 | by the name of your form type class (DateTimePickerType -> date_time_picker)
4 | and the suffix "_widget". This can be controlled by overriding getBlockPrefix()
5 | in DateTimePickerType.
6 |
7 | See https://symfony.com/doc/current/cookbook/form/create_custom_field_type.html#creating-a-template-for-the-field
8 | #}
9 |
10 | {% block date_time_picker_widget %}
11 |
12 | {{ block('datetime_widget') }}
13 |
14 |
15 |
16 |
17 | {% endblock %}
18 |
19 | {% block tags_input_widget %}
20 |
21 | {{ form_widget(form, {'attr': {'data-toggle': 'tagsinput', 'data-tags': tags|json_encode}}) }}
22 |
23 |
24 |
25 |
26 | {% endblock %}
27 |
--------------------------------------------------------------------------------
/templates/form/layout.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'bootstrap_3_layout.html.twig' %}
2 |
3 | {# Errors #}
4 |
5 | {% block form_errors -%}
6 | {% if errors|length > 0 -%}
7 | {% if form is not rootform %}{% else %}{% endif %}
8 |
9 | {%- for error in errors -%}
10 | {# use font-awesome icon library #}
11 | {{ error.message }}
12 | {%- endfor -%}
13 |
14 | {% if form is not rootform %}{% else %}
{% endif %}
15 | {%- endif %}
16 | {%- endblock form_errors %}
17 |
--------------------------------------------------------------------------------
/templates/user/change_password.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block body_id 'user_password' %}
4 |
5 | {% block main %}
6 | {{ 'title.change_password'|trans }}
7 |
8 | {{ 'info.change_password'|trans }}
9 |
10 | {{ form_start(form) }}
11 | {{ form_widget(form) }}
12 |
13 |
14 | {{ 'action.save'|trans }}
15 |
16 | {{ form_end(form) }}
17 | {% endblock %}
18 |
19 | {% block sidebar %}
20 |
25 |
26 | {{ parent() }}
27 |
28 | {{ show_source_code(_self) }}
29 | {% endblock %}
30 |
--------------------------------------------------------------------------------
/templates/user/edit.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block body_id 'user_edit' %}
4 |
5 | {% block main %}
6 | {{ 'title.edit_user'|trans }}
7 |
8 | {{ form_start(form) }}
9 | {{ form_widget(form) }}
10 |
11 |
12 | {{ 'action.save'|trans }}
13 |
14 | {{ form_end(form) }}
15 | {% endblock %}
16 |
17 | {% block sidebar %}
18 |
23 |
24 | {{ parent() }}
25 |
26 | {{ show_source_code(_self) }}
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/tests/Controller/BlogControllerTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace App\Tests\Controller;
13 |
14 | use App\Entity\Post;
15 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
16 |
17 | /**
18 | * Functional test for the controllers defined inside BlogController.
19 | *
20 | * See https://symfony.com/doc/current/book/testing.html#functional-tests
21 | *
22 | * Execute the application tests using this command (requires PHPUnit to be installed):
23 | *
24 | * $ cd your-symfony-project/
25 | * $ ./vendor/bin/phpunit
26 | */
27 | class BlogControllerTest extends WebTestCase
28 | {
29 | public function testIndex()
30 | {
31 | $client = static::createClient();
32 | $crawler = $client->request('GET', '/en/blog/');
33 |
34 | $this->assertCount(
35 | Post::NUM_ITEMS,
36 | $crawler->filter('article.post'),
37 | 'The homepage displays the right number of posts.'
38 | );
39 | }
40 |
41 | public function testRss()
42 | {
43 | $client = static::createClient();
44 | $crawler = $client->request('GET', '/en/blog/rss.xml');
45 |
46 | $this->assertSame(
47 | 'text/xml; charset=UTF-8',
48 | $client->getResponse()->headers->get('Content-Type')
49 | );
50 |
51 | $this->assertCount(
52 | Post::NUM_ITEMS,
53 | $crawler->filter('item'),
54 | 'The xml file displays the right number of posts.'
55 | );
56 | }
57 |
58 | /**
59 | * This test changes the database contents by creating a new comment. However,
60 | * thanks to the DAMADoctrineTestBundle and its PHPUnit listener, all changes
61 | * to the database are rolled back when this test completes. This means that
62 | * all the application tests begin with the same database contents.
63 | */
64 | public function testNewComment()
65 | {
66 | $client = static::createClient([], [
67 | 'PHP_AUTH_USER' => 'john_user',
68 | 'PHP_AUTH_PW' => 'kitten',
69 | ]);
70 | $client->followRedirects();
71 |
72 | // Find first blog post
73 | $crawler = $client->request('GET', '/en/blog/');
74 | $postLink = $crawler->filter('article.post > h2 a')->link();
75 |
76 | $crawler = $client->click($postLink);
77 |
78 | $form = $crawler->selectButton('Publish comment')->form([
79 | 'comment[content]' => 'Hi, Symfony!',
80 | ]);
81 | $crawler = $client->submit($form);
82 |
83 | $newComment = $crawler->filter('.post-comment')->first()->filter('div > p')->text();
84 |
85 | $this->assertSame('Hi, Symfony!', $newComment);
86 | }
87 |
88 | public function testAjaxSearch()
89 | {
90 | $client = static::createClient();
91 | $client->xmlHttpRequest('GET', '/en/blog/search', ['q' => 'lorem']);
92 |
93 | $results = json_decode($client->getResponse()->getContent(), true);
94 |
95 | $this->assertSame('application/json', $client->getResponse()->headers->get('Content-Type'));
96 | $this->assertCount(1, $results);
97 | $this->assertSame('Lorem ipsum dolor sit amet consectetur adipiscing elit', $results[0]['title']);
98 | $this->assertSame('Jane Doe', $results[0]['author']);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/tests/Controller/DefaultControllerTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace App\Tests\Controller;
13 |
14 | use App\Entity\Post;
15 | use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
16 | use Symfony\Component\HttpFoundation\Response;
17 |
18 | /**
19 | * Functional test that implements a "smoke test" of all the public and secure
20 | * URLs of the application.
21 | * See https://symfony.com/doc/current/best_practices/tests.html#functional-tests.
22 | *
23 | * Execute the application tests using this command (requires PHPUnit to be installed):
24 | *
25 | * $ cd your-symfony-project/
26 | * $ ./vendor/bin/phpunit
27 | */
28 | class DefaultControllerTest extends WebTestCase
29 | {
30 | /**
31 | * PHPUnit's data providers allow to execute the same tests repeated times
32 | * using a different set of data each time.
33 | * See https://symfony.com/doc/current/cookbook/form/unit_testing.html#testing-against-different-sets-of-data.
34 | *
35 | * @dataProvider getPublicUrls
36 | */
37 | public function testPublicUrls(string $url)
38 | {
39 | $client = static::createClient();
40 | $client->request('GET', $url);
41 |
42 | $this->assertSame(
43 | Response::HTTP_OK,
44 | $client->getResponse()->getStatusCode(),
45 | sprintf('The %s public URL loads correctly.', $url)
46 | );
47 | }
48 |
49 | /**
50 | * A good practice for tests is to not use the service container, to make
51 | * them more robust. However, in this example we must access to the container
52 | * to get the entity manager and make a database query. The reason is that
53 | * blog post fixtures are randomly generated and there's no guarantee that
54 | * a given blog post slug will be available.
55 | */
56 | public function testPublicBlogPost()
57 | {
58 | $client = static::createClient();
59 | // the service container is always available via the test client
60 | $blogPost = $client->getContainer()->get('doctrine')->getRepository(Post::class)->find(1);
61 | $client->request('GET', sprintf('/en/blog/posts/%s', $blogPost->getSlug()));
62 |
63 | $this->assertSame(Response::HTTP_OK, $client->getResponse()->getStatusCode());
64 | }
65 |
66 | /**
67 | * The application contains a lot of secure URLs which shouldn't be
68 | * publicly accessible. This tests ensures that whenever a user tries to
69 | * access one of those pages, a redirection to the login form is performed.
70 | *
71 | * @dataProvider getSecureUrls
72 | */
73 | public function testSecureUrls(string $url)
74 | {
75 | $client = static::createClient();
76 | $client->request('GET', $url);
77 |
78 | $response = $client->getResponse();
79 | $this->assertSame(Response::HTTP_FOUND, $response->getStatusCode());
80 | $this->assertSame(
81 | 'http://localhost/en/login',
82 | $response->getTargetUrl(),
83 | sprintf('The %s secure URL redirects to the login form.', $url)
84 | );
85 | }
86 |
87 | public function getPublicUrls()
88 | {
89 | yield ['/'];
90 | yield ['/en/blog/'];
91 | yield ['/en/login'];
92 | }
93 |
94 | public function getSecureUrls()
95 | {
96 | yield ['/en/admin/post/'];
97 | yield ['/en/admin/post/new'];
98 | yield ['/en/admin/post/1'];
99 | yield ['/en/admin/post/1/edit'];
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/tests/Utils/SluggerTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace App\Tests\Utils;
13 |
14 | use App\Utils\Slugger;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | /**
18 | * Unit test for the application utils.
19 | *
20 | * See https://symfony.com/doc/current/book/testing.html#unit-tests
21 | *
22 | * Execute the application tests using this command (requires PHPUnit to be installed):
23 | *
24 | * $ cd your-symfony-project/
25 | * $ ./vendor/bin/phpunit
26 | */
27 | class SluggerTest extends TestCase
28 | {
29 | /**
30 | * @dataProvider getSlugs
31 | */
32 | public function testSlugify(string $string, string $slug)
33 | {
34 | $this->assertSame($slug, Slugger::slugify($string));
35 | }
36 |
37 | public function getSlugs()
38 | {
39 | yield ['Lorem Ipsum', 'lorem-ipsum'];
40 | yield [' Lorem Ipsum ', 'lorem-ipsum'];
41 | yield [' lOrEm iPsUm ', 'lorem-ipsum'];
42 | yield ['!Lorem Ipsum!', '!lorem-ipsum!'];
43 | yield ['lorem-ipsum', 'lorem-ipsum'];
44 | yield ['lorem 日本語 ipsum', 'lorem-日本語-ipsum'];
45 | yield ['lorem русский язык ipsum', 'lorem-русский-язык-ipsum'];
46 | yield ['lorem العَرَبِيَّة ipsum', 'lorem-العَرَبِيَّة-ipsum'];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Utils/ValidatorTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace App\Tests\Utils;
13 |
14 | use App\Utils\Validator;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | class ValidatorTest extends TestCase
18 | {
19 | private $object;
20 |
21 | public function __construct()
22 | {
23 | parent::__construct();
24 |
25 | $this->object = new Validator();
26 | }
27 |
28 | public function testValidateUsername()
29 | {
30 | $test = 'username';
31 |
32 | $this->assertSame($test, $this->object->validateUsername($test));
33 | }
34 |
35 | public function testValidateUsernameEmpty()
36 | {
37 | $this->expectException('Exception');
38 | $this->expectExceptionMessage('The username can not be empty.');
39 | $this->object->validateUsername(null);
40 | }
41 |
42 | public function testValidateUsernameInvalid()
43 | {
44 | $this->expectException('Exception');
45 | $this->expectExceptionMessage('The username must contain only lowercase latin characters and underscores.');
46 | $this->object->validateUsername('INVALID');
47 | }
48 |
49 | public function testValidatePassword()
50 | {
51 | $test = 'password';
52 |
53 | $this->assertSame($test, $this->object->validatePassword($test));
54 | }
55 |
56 | public function testValidatePasswordEmpty()
57 | {
58 | $this->expectException('Exception');
59 | $this->expectExceptionMessage('The password can not be empty.');
60 | $this->object->validatePassword(null);
61 | }
62 |
63 | public function testValidatePasswordInvalid()
64 | {
65 | $this->expectException('Exception');
66 | $this->expectExceptionMessage('The password must be at least 6 characters long.');
67 | $this->object->validatePassword('12345');
68 | }
69 |
70 | public function testValidateEmail()
71 | {
72 | $test = '@';
73 |
74 | $this->assertSame($test, $this->object->validateEmail($test));
75 | }
76 |
77 | public function testValidateEmailEmpty()
78 | {
79 | $this->expectException('Exception');
80 | $this->expectExceptionMessage('The email can not be empty.');
81 | $this->object->validateEmail(null);
82 | }
83 |
84 | public function testValidateEmailInvalid()
85 | {
86 | $this->expectException('Exception');
87 | $this->expectExceptionMessage('The email should look like a real email.');
88 | $this->object->validateEmail('invalid');
89 | }
90 |
91 | public function testValidateFullName()
92 | {
93 | $test = 'Full Name';
94 |
95 | $this->assertSame($test, $this->object->validateFullName($test));
96 | }
97 |
98 | public function testValidateFullNameEmpty()
99 | {
100 | $this->expectException('Exception');
101 | $this->expectExceptionMessage('The full name can not be empty.');
102 | $this->object->validateFullName(null);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.bg.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Напишете обобщение на публикацията си!
8 |
9 |
10 | post.blank_content
11 | Публикацията трябва да има съдържание!
12 |
13 |
14 | post.too_short_content
15 | Съдержанието на публикацията е прекалено малко ({ limit } минимум символа)
16 |
17 |
18 | post.too_many_tags
19 | Прекалено много тагове (добави { limit } тага или по-малко)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.ca.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | No és possible deixar buit el resum de l'article.
8 |
9 |
10 | post.blank_content
11 | No és possible deixar buit el contingut de l'article.
12 |
13 |
14 | post.too_short_content
15 | El contingut de l'article és massa curt ({ limit } caràcters com a mínim)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.cs.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Napište shrnutí příspěvku!
8 |
9 |
10 | post.too_short_content
11 | Příspěvek je příliš krátký (musí mít minimálně { limit } znak)|Příspěvek je příliš krátký (musí mít minimálně { limit } znaky)|Příspěvek je příliš krátký (musí mít minimálně { limit } znaků)
12 |
13 |
17 |
21 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.de.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Gib deinem Beitrag eine Zusammenfassung!
8 |
9 |
10 | post.blank_content
11 | Dein Beitrag sollte einen Inhalt haben!
12 |
13 |
14 | post.too_short_content
15 | Der Beitragsinhalt ist zu kurz (mindestens { limit } Zeichen)
16 |
17 |
21 |
25 |
29 |
33 |
34 | post.too_many_tags
35 | Zu viele Tags (höchstens { limit } Tags sind erlaubt)
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.en.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Give your post a summary!
8 |
9 |
10 | post.blank_content
11 | Your post should have some content!
12 |
13 |
14 | post.too_short_content
15 | Post content is too short ({ limit } characters minimum)
16 |
17 |
18 | post.too_many_tags
19 | Too many tags (add { limit } tags or less)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.es.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | No es posible dejar el resumen del artículo vacío.
8 |
9 |
10 | post.blank_content
11 | No es posible dejar el contenido del artículo vacío.
12 |
13 |
14 | post.too_short_content
15 | El contenido del artículo es demasiado corto ({ limit } caracteres como mínimo)
16 |
17 |
18 | post.too_many_tags
19 | Demasiadas etiquetas (añade { limit } como máximo)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.fr.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Veuillez donner un résumé à votre post.
8 |
9 |
10 | post.blank_content
11 | Veuillez donner un contenu à votre post.
12 |
13 |
14 | post.too_short_content
15 | Le contenu de votre post est trop court ({ limit } caractères minimum)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.hr.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Dodajte sažetak svojem članku!
8 |
9 |
10 | post.blank_content
11 | Vaš članak treba imati sadržaj!
12 |
13 |
14 | post.too_short_content
15 | Sadržaj članka je prekratak (koristiti minimalno { limit } slova ili simbola)
16 |
17 |
18 | post.too_many_tags
19 | Previše oznaka (dodaj najviše { limit } oznaka ili manje)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.id.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Beri posting anda ringkasan!
8 |
9 |
10 | post.blank_content
11 | Posting anda harus mempunyai konten!
12 |
13 |
14 | post.too_short_content
15 | Konten terlalu singkat (Minimal { limit } karakter)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.it.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Da' una descrizione al tuo post!
8 |
9 |
10 | post.blank_content
11 | Da' un contenuto al tuo post!
12 |
13 |
14 | post.too_short_content
15 | Il contenuto del post è troppo breve (minimo { limit } caratteri)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.ja.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | 要約を入力してください。
8 |
9 |
10 | post.blank_content
11 | 本文を入力してください。
12 |
13 |
14 | post.too_short_content
15 | 本文が短すぎます ({ limit } 文字以上必要です)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.lt.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Įrašo santrauka negali būti tuščia
8 |
9 |
10 | post.blank_content
11 | Įrašo turinys negali būti tuščias
12 |
13 |
14 | post.too_short_content
15 | Per trumpas įrašo turinys (nesiekia { limit } simbolių)
16 |
17 |
18 | post.too_many_tags
19 | Per daug žymų (viršyja { limit })
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.nl.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Geef uw bericht een samenvatting.
8 |
9 |
10 | post.blank_content
11 | Uw bericht heeft nog geen inhoud.
12 |
13 |
14 | post.too_short_content
15 | Bericht inhoud is te kort (minimaal { limit } karakters)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.pl.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Dodaj podsumowanie Twojego artykułu!
8 |
9 |
10 | post.blank_content
11 | Treść artykułu nie może być pusta!
12 |
13 |
14 | post.too_short_content
15 | Treść artykułu jest za krótka (minimum: { limit } znak)|Treść artykułu jest za krótka (minimum: { limit } znaki)|Treść artykułu jest za krótka (minimum: { limit } znaków)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.pt_BR.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Informe um sumário para o seu post!
8 |
9 |
10 | post.blank_content
11 | Informe um conteúdo para o seu post!
12 |
13 |
14 | post.too_short_content
15 | O conteúdo do post está muito curto (mínimo de { limit } caracteres)
16 |
17 |
18 | post.too_many_tags
19 | Tags demais (adicione { limit } tags ou menos)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.ro.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Dă articolului tău un rezumat!
8 |
9 |
10 | post.blank_content
11 | Articolul ar trebui să aibe conținut!
12 |
13 |
14 | post.too_short_content
15 | Conţinutul articolului este prea scurt (minimum { limit } caractere)
16 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.ru.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Введите краткое содержание вашей записи!
8 |
9 |
10 | post.blank_content
11 | Ваша запись должна содержать хоть какое-то содержание!
12 |
13 |
14 | post.too_short_content
15 | Содержание записи слишком короткое (минимум { limit } символов).
16 |
17 |
18 | post.too_many_tags
19 | Слишком много тегов (добавьте { limit } тегов или меньше)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.sl.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Dodajte vaši objavi povzetek!
8 |
9 |
10 | post.blank_content
11 | Vaša objava mora imeti nekaj vsebine!
12 |
13 |
14 | post.too_short_content
15 | Vsebina objave je prekratka (vsaj { limit } znakov)
16 |
17 |
18 | post.too_many_tags
19 | Preveč značk (dodajte { limit } ali manj značk)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.tr.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Gönderiniz için bir özet giriniz!
8 |
9 |
10 | post.blank_content
11 | Gönderiniz bir içeriğe sahip olmalı!
12 |
13 |
14 | post.too_short_content
15 | Yayın içeriği çok kısa ({ limit } minimum karakter)
16 |
17 |
18 | post.too_many_tags
19 | Çok fazla etiket var ({ limit } etiketini veya daha azını ekleyin)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.uk.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | Введіть короткий зміст вашого запису!
8 |
9 |
10 | post.blank_content
11 | Ваш запис повинен містити хоч якийсь зміст!
12 |
13 |
14 | post.too_short_content
15 | Зміст запису занадто короткий (мінімум { limit } символів).
16 |
17 |
18 | post.too_many_tags
19 | Занадто багато тегів (додайте { limit } тегів або менше)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.zh_CN.xlf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | post.blank_summary
7 | 请填写文章摘要!
8 |
9 |
10 | post.blank_content
11 | 请填写文章内容!
12 |
13 |
14 | post.too_short_content
15 | 文章内容太少 最少 ({ limit } 个字 )
16 |
17 |
18 | post.too_many_tags
19 | 标签太多 (最多 { limit } 个标签)
20 |
21 |
25 |
29 |
33 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/var/log/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geshan/symfony-demo-google-cloud-run/e1fbea609aa72f79ea57fcaaad86e8764e1f35ad/var/log/.gitkeep
--------------------------------------------------------------------------------
/var/sessions/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geshan/symfony-demo-google-cloud-run/e1fbea609aa72f79ea57fcaaad86e8764e1f35ad/var/sessions/.gitkeep
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | // This project uses "Yarn" package manager for managing JavaScript dependencies along
2 | // with "Webpack Encore" library that helps working with the CSS and JavaScript files
3 | // that are stored in the "assets/" directory.
4 | //
5 | // Read https://symfony.com/doc/current/frontend.html to learn more about how
6 | // to manage CSS and JavaScript files in Symfony applications.
7 | var Encore = require('@symfony/webpack-encore');
8 |
9 | Encore
10 | .setOutputPath('public/build/')
11 | .setPublicPath('/build')
12 | .cleanupOutputBeforeBuild()
13 | .autoProvidejQuery()
14 | .autoProvideVariables({
15 | "window.Bloodhound": require.resolve('bloodhound-js'),
16 | "jQuery.tagsinput": "bootstrap-tagsinput"
17 | })
18 | .enableSassLoader()
19 | // when versioning is enabled, each filename will include a hash that changes
20 | // whenever the contents of that file change. This allows you to use aggressive
21 | // caching strategies. Use Encore.isProduction() to enable it only for production.
22 | .enableVersioning(false)
23 | .addEntry('app', './assets/js/app.js')
24 | .addEntry('login', './assets/js/login.js')
25 | .addEntry('admin', './assets/js/admin.js')
26 | .addEntry('search', './assets/js/search.js')
27 | .splitEntryChunks()
28 | .enableSingleRuntimeChunk()
29 | .enableIntegrityHashes(Encore.isProduction())
30 | .configureBabel(null, {
31 | useBuiltIns: 'usage',
32 | corejs: 3,
33 | })
34 | ;
35 |
36 | module.exports = Encore.getWebpackConfig();
37 |
--------------------------------------------------------------------------------
44 | {{ comment.author.fullName }} {{ 'post.commented_on'|trans }} 45 | {# it's not mandatory to set the timezone in localizeddate(). This is done to 46 | avoid errors when the 'intl' PHP extension is not available and the application 47 | is forced to use the limited "intl polyfill", which only supports UTC and GMT #} 48 | {{ comment.publishedAt|localizeddate('medium', 'short', null, 'UTC') }} 49 |
50 |