before recepie upgrade

This commit is contained in:
tracer 2021-06-14 19:20:55 +02:00
parent e273b81925
commit 3fa30dbde4
19 changed files with 284 additions and 88 deletions

View File

@ -5,9 +5,5 @@ require('bootstrap');
import '../styles/app.scss';
$(document).ready(function() {
$('.navbarDropdown').dropdown();
});
require('@fortawesome/fontawesome-free/css/all.min.css');
require('@fortawesome/fontawesome-free/js/all.js');

View File

@ -11,7 +11,7 @@
/* debug */
* {
border: 0 solid gray;
border: 1px solid gray;
}
// customize some Bootstrap variables

View File

@ -3,41 +3,15 @@
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\ErrorHandler\Debug;
if (!in_array(PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
echo 'Warning: The console should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
set_time_limit(0);
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
require dirname(__DIR__).'/vendor/autoload.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
if (!class_exists(Application::class) || !class_exists(Dotenv::class)) {
throw new LogicException('You need to add "symfony/framework-bundle" and "symfony/dotenv" as Composer dependencies.');
}
$input = new ArgvInput();
if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) {
putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
}
if ($input->hasParameterOption('--no-debug', true)) {
putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
}
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
if ($_SERVER['APP_DEBUG']) {
umask(0000);
if (class_exists(Debug::class)) {
Debug::enable();
}
}
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$application = new Application($kernel);
$application->run($input);
return new Application($kernel);
};

View File

@ -22,6 +22,7 @@
"symfony/monolog-bundle": "^3.7",
"symfony/proxy-manager-bridge": "5.3.*",
"symfony/security-bundle": "5.3.*",
"symfony/string": "5.3.*",
"symfony/twig-bundle": "^5.2",
"symfony/validator": "5.3.*",
"symfony/webpack-encore-bundle": "^1.11",

15
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "34381deb043c87393a1f92bbeab2aaff",
"content-hash": "f801003bc6731e7d38ee4787d3a9489a",
"packages": [
{
"name": "composer/package-versions-deprecated",
@ -6750,16 +6750,16 @@
},
{
"name": "symfony/validator",
"version": "v5.3.0",
"version": "v5.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
"reference": "14337bdf9e2e0b2e3385c9e90f13325f0c95a4f9"
"reference": "111e71ac585a47358e808bc687dcaf66e568470a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/validator/zipball/14337bdf9e2e0b2e3385c9e90f13325f0c95a4f9",
"reference": "14337bdf9e2e0b2e3385c9e90f13325f0c95a4f9",
"url": "https://api.github.com/repos/symfony/validator/zipball/111e71ac585a47358e808bc687dcaf66e568470a",
"reference": "111e71ac585a47358e808bc687dcaf66e568470a",
"shasum": ""
},
"require": {
@ -6778,6 +6778,7 @@
"symfony/expression-language": "<5.1",
"symfony/http-kernel": "<4.4",
"symfony/intl": "<4.4",
"symfony/property-info": "<5.3",
"symfony/translation": "<4.4",
"symfony/yaml": "<4.4"
},
@ -6839,7 +6840,7 @@
"description": "Provides tools to validate values",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/validator/tree/v5.3.0"
"source": "https://github.com/symfony/validator/tree/v5.3.1"
},
"funding": [
{
@ -6855,7 +6856,7 @@
"type": "tidelift"
}
],
"time": "2021-05-26T17:43:10+00:00"
"time": "2021-06-02T09:36:17+00:00"
},
{
"name": "symfony/var-dumper",

View File

@ -1,5 +1,5 @@
security:
encoders:
password_hashers:
App\Entity\User:
algorithm: auto
@ -10,12 +10,14 @@ security:
entity:
class: App\Entity\User
property: username
enable_authenticator_manager: true
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
lazy: true
provider: app_user_provider
guard:
@ -35,5 +37,6 @@ security:
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin/login, roles: PUBLIC_ACCESS }
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }

View File

@ -1,3 +1,3 @@
twig:
default_path: '%kernel.project_dir%/templates'
form_themes: ['bootstrap_4_layout.html.twig']
form_themes: ['bootstrap_5_layout.html.twig']

View File

@ -33,3 +33,7 @@ services:
- '%env(DATABASE_URL)%'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\EntityListener\BlogEntityListener:
tags:
- { name: 'doctrine.orm.entity_listener', event: 'prePersist', entity: 'App\Entity\Blog'}
- { name: 'doctrine.orm.entity_listener', event: 'preUpdate', entity: 'App\Entity\Blog'}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210614155532 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE UNIQUE INDEX UNIQ_C0155143989D9B62 ON blog (slug)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_C0155143989D9B62 ON blog');
}
}

View File

@ -6,6 +6,7 @@ use App\Entity\Blog;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\SlugField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
@ -26,7 +27,8 @@ class BlogCrudController extends AbstractCrudController
AssociationField::new('author')
->autocomplete(),
TextField::new('title'),
TextField::new('slug'),
SlugField::new('slug')
->setTargetFieldName('title'),
TextEditorField::new('teaser'),
TextEditorField::new('content'),
DateTimeField::new('createdAt'),

View File

@ -3,8 +3,12 @@
namespace App\Controller;
use App\Entity\Blog;
use App\Form\BlogFormType;
use App\Repository\BlogRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@ -18,22 +22,76 @@ class BlogController extends AbstractController
public function index(BlogRepository $blogRepository): Response
{
return $this->render('blog/index.html.twig', [
'blogs' => $blogRepository->findAll()
'blogs' => $blogRepository->findAll()
]);
}
/**
* @param $id
* @param $slug
* @param \App\Repository\BlogRepository $blogRepository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route('/blog/{slug}', name: 'blog')]
#[Route('/blog_show/{slug}', name: 'blog')]
public function show($slug, BlogRepository $blogRepository): Response
{
return $this->render('blog/show.html.twig', [
'blog' => $blogRepository->findOneBy(['slug' => $slug])
'blog' => $blogRepository->findOneBy(['slug' => $slug])
]);
}
/**
* @param \Doctrine\ORM\EntityManagerInterface $entityManager
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
#[Route('/blog/new', name: 'blog_new')]
public function new(EntityManagerInterface $entityManager, Request $request): RedirectResponse|Response
{
$form = $this->createForm(BlogFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$blog = $form->getData();
$entityManager->persist($blog);
$entityManager->flush();
return $this->redirectToRoute('blogs');
}
return $this->render('blog/new.html.twig', [
'blogForm' => $form->createView(),
]);
}
/**
* @param \App\Entity\Blog $blog
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
#[Route('/blog/edit/{id}', name: 'blog_edit')]
public function edit(Blog $blog, Request $request): Response|RedirectResponse
{
$form = $this->createForm(BlogFormType::class, $blog);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$blog = $form->getData();
//$blog->setAuthor($this->getUser());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($blog);
$entityManager->flush();
return $this->redirectToRoute('blogs');
}
return $this->render('blog/new.html.twig', [
'blogForm' => $form->createView(),
]);
}
}

View File

@ -7,11 +7,13 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JetBrains\PhpStorm\Pure;
use App\Repository\SectionRepository;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\String\Slugger\SluggerInterface;
/**
* @ORM\Entity(repositoryClass=BlogRepository::class)
* @ORM\HasLifecycleCallbacks()
* @UniqueEntity("slug")
*/
class Blog
{
@ -79,7 +81,7 @@ class Blog
private $comments;
/**
* @ORM\Column(type="string", length=255)
* @ORM\Column(type="string", length=255, unique=true)
*/
private $slug;
@ -274,7 +276,24 @@ class Blog
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
/**
* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->createdAt = new \DateTime();
}
/**
* @param SluggerInterface $slugger
*/
public function computeSlug(SluggerInterface $slugger)
{
$this->slug = $slugger->slug($this->title);
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\EntityListener;
use App\Entity\Blog;
use Doctrine\ORM\Event\LifecycleEventArgs;
use JetBrains\PhpStorm\NoReturn;
use Symfony\Component\String\Slugger\SluggerInterface;
/**
* Class BlogEntityListener
* @package App\EntityListener
*/
class BlogEntityListener
{
private SluggerInterface $slugger;
public function __construct(SluggerInterface $slugger)
{
$this->slugger = $slugger;
}
/**
* @param \App\Entity\Blog $blog
* @param \Doctrine\ORM\Event\LifecycleEventArgs $title
*/
#[NoReturn]
public function prePersist(Blog $blog, LifecycleEventArgs $title)
{
$blog->computeSlug($this->slugger);
}
/**
* @param \App\Entity\Blog $blog
* @param \Doctrine\ORM\Event\LifecycleEventArgs $title
*/
#[NoReturn]
public function preUpdate(Blog $blog, LifecycleEventArgs $title)
{
//dd($title);
$blog->computeSlug($this->slugger);
}
}

40
src/Form/BlogFormType.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace App\Form;
use App\Entity\Blog;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class BlogFormType
* @package App\Form
*/
class BlogFormType extends \Symfony\Component\Form\AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('teaser')
->add('content')
->add('author');
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Blog::class
]);
}
}

View File

@ -7,12 +7,12 @@ use Doctrine\ORM\EntityManagerInterface;
use JetBrains\PhpStorm\ArrayShape;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
@ -22,23 +22,27 @@ use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticato
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
/**
* Class AppAuthenticator
* @package App\Security
*/
class AppAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
private EntityManagerInterface $entityManager;
private UrlGeneratorInterface $urlGenerator;
private CsrfTokenManagerInterface $csrfTokenManager;
private UserPasswordHasherInterface $passwordHasher;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordHasherInterface $passwordHasher)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
$this->passwordHasher = $passwordHasher;
}
/**
@ -109,7 +113,7 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor
* @throws AuthenticationException
*
*/
public function getUser($credentials, UserProviderInterface $userProvider)
public function getUser($credentials, UserProviderInterface $userProvider): ?UserInterface
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
@ -125,7 +129,7 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor
}
if (!$user) {
throw new UsernameNotFoundException('Username or email could not be found.');
throw new UserNotFoundException('Username or email could not be found.');
} else {
return $user;
}
@ -149,7 +153,7 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor
public function checkCredentials($credentials, UserInterface $user): bool
{
//return true;
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
return $this->passwordHasher->isPasswordValid($user, $credentials['password']);
}
/**
@ -160,6 +164,17 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor
return $credentials['password'];
}
/**
* Called when authentication executed and was successful!
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the last page they visited.
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* @return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
@ -174,15 +189,3 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
/*
comment:
author => user,
createdAt,
editedAt,
editedby => user,
editreason
*/

View File

@ -140,12 +140,12 @@
"version": "v5.2.8"
},
"symfony/console": {
"version": "5.1",
"version": "5.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "5.1",
"ref": "c6d02bdfba9da13c22157520e32a602dbee8a75c"
"version": "5.3",
"ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
},
"files": [
"bin/console"

View File

@ -10,14 +10,16 @@
<div class="collapse navbar-collapse" id="CollapsingNavbar">
<ul class="navbar-nav ms-auto">
<form class="d-flex">
<input class="form-control me-2 my-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn" type="submit">Search</button>
</form>
<li>
<form class="d-flex">
<input class="form-control me-2 my-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn" type="submit">Search</button>
</form>
</li>
{% if is_granted('ROLE_USER') %}
<li class="nav-item dropdown me-auto my-2 my-lg-0">
<li class="nav-item dropdown me-auto">
<button type="button" id="navbar-dropdown" data-bs-target="#dropdown-menu" data-bs-toggle="dropdown"
class="btn btn-primary dropdown-toggle ml-auto button-login">
class="btn btn-primary dropdown-toggle ml-auto mb-2 button-login">
{{ app.user.username }}
</button>

View File

@ -0,0 +1,15 @@
{% extends 'base.html.twig' %}
{% block body %}
Create new Blog
{{ form_start(blogForm) }}
{{ form_widget(blogForm) }}
<button type="submit" class="btn btn-primary">Create</button>
{{ form_end(blogForm) }}
{% endblock %}
{% block title %}
New Blog
{% endblock %}

View File

@ -11,6 +11,10 @@
<div class="show-article-container p-3 mt-4">
<div class="row">
<div class="col-sm-12">
<div class="">
<a href="{{ path('blog_edit', { id : blog.id }) }}"><i class="fas fa-edit"></i></a>
<a href="{{ path('blogs') }}"><i class="fas fa-trash-alt"></i></a>
</div>
<img class="show-article-img" src="{{ asset('build/images/asteroid.jpeg') }}" alt="asteroid">
<div class="show-article-title-container d-inline-block pl-3 align-middle">
<span class="show-article-title ">{{ blog.title }}</span>