First fully working version of saving snips content with git control
This commit is contained in:
parent
1a7c9bb25a
commit
842c936d8c
@ -7,6 +7,7 @@
|
|||||||
"php": ">=8.1",
|
"php": ">=8.1",
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
|
"czproject/git-php": "^4.1",
|
||||||
"doctrine/doctrine-bundle": "^2.9",
|
"doctrine/doctrine-bundle": "^2.9",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.2",
|
"doctrine/doctrine-migrations-bundle": "^3.2",
|
||||||
"doctrine/orm": "^2.14",
|
"doctrine/orm": "^2.14",
|
||||||
|
54
composer.lock
generated
54
composer.lock
generated
@ -4,8 +4,60 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "5cd09d345b4ecefaece6f03c919d953e",
|
"content-hash": "975714eae301e2eb9cd72cfce038b337",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "czproject/git-php",
|
||||||
|
"version": "v4.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/czproject/git-php.git",
|
||||||
|
"reference": "bb195e30442bc5206b30fa9a304e20ea8e96458f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/czproject/git-php/zipball/bb195e30442bc5206b30fa9a304e20ea8e96458f",
|
||||||
|
"reference": "bb195e30442bc5206b30fa9a304e20ea8e96458f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.6.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"nette/tester": "^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jan Pecha",
|
||||||
|
"email": "janpecha@email.cz"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Library for work with Git repository in PHP.",
|
||||||
|
"keywords": [
|
||||||
|
"git"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/czproject/git-php/issues",
|
||||||
|
"source": "https://github.com/czproject/git-php/tree/v4.1.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.paypal.com/donate?hosted_button_id=EPSKR7MGVV7KC",
|
||||||
|
"type": "custom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2022-12-10T18:23:32+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/cache",
|
"name": "doctrine/cache",
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
|
@ -23,3 +23,7 @@ services:
|
|||||||
App\Service\LastRelease:
|
App\Service\LastRelease:
|
||||||
arguments:
|
arguments:
|
||||||
- '%kernel.project_dir%/release.json'
|
- '%kernel.project_dir%/release.json'
|
||||||
|
|
||||||
|
App\Service\SnipServiceFactory:
|
||||||
|
arguments:
|
||||||
|
- '%kernel.project_dir%/var/snips'
|
@ -5,6 +5,7 @@ namespace App\Controller;
|
|||||||
use App\Entity\Snip;
|
use App\Entity\Snip;
|
||||||
use App\Form\SnipType;
|
use App\Form\SnipType;
|
||||||
use App\Repository\SnipRepository;
|
use App\Repository\SnipRepository;
|
||||||
|
use App\Service\SnipServiceFactory;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@ -16,6 +17,7 @@ class SnipController extends AbstractController
|
|||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly SnipRepository $repository,
|
private readonly SnipRepository $repository,
|
||||||
|
private readonly SnipServiceFactory $snipServiceFactory,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -24,22 +26,26 @@ class SnipController extends AbstractController
|
|||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
return $this->render('snip/index.html.twig', [
|
return $this->render('snip/index.html.twig', [
|
||||||
'snips' => $this->repository->findAll(),
|
'snips' => $this->repository->findByUser($this->getUser()),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/singe/{snip}', name: '_single')]
|
#[Route('/single/{snip}', name: '_single')]
|
||||||
public function single(Snip $snip): Response
|
public function single(Snip $snip): Response
|
||||||
{
|
{
|
||||||
return $this->render('snip/single.html.twig', [
|
return $this->render('snip/single.html.twig', [
|
||||||
'snip' => $snip,
|
'snip' => $snip,
|
||||||
|
'content' => $this->snipServiceFactory->create($snip)->get(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/edit/{snip}', name: '_edit')]
|
#[Route('/edit/{snip}', name: '_edit')]
|
||||||
public function edit(Snip $snip, Request $request): Response
|
public function edit(Snip $snip, Request $request): Response
|
||||||
{
|
{
|
||||||
|
$snipService = $this->snipServiceFactory->create($snip);
|
||||||
|
|
||||||
$form = $this->createForm(SnipType::class, $snip);
|
$form = $this->createForm(SnipType::class, $snip);
|
||||||
|
$form->get('content')->setData($snipService->get());
|
||||||
$form->add('Save', SubmitType::class);
|
$form->add('Save', SubmitType::class);
|
||||||
|
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
@ -47,6 +53,7 @@ class SnipController extends AbstractController
|
|||||||
$snip->setCreatedAtTodayNoSeconds()
|
$snip->setCreatedAtTodayNoSeconds()
|
||||||
->setCreatedBy($this->getUser());
|
->setCreatedBy($this->getUser());
|
||||||
$this->repository->save($snip);
|
$this->repository->save($snip);
|
||||||
|
$snipService->update($form->get('content')->getData());
|
||||||
|
|
||||||
$this->addFlash('success', sprintf('Snip "%s" saved successfully', $snip));
|
$this->addFlash('success', sprintf('Snip "%s" saved successfully', $snip));
|
||||||
|
|
||||||
|
@ -40,11 +40,6 @@ trait TrackedTrait
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCode(): string
|
|
||||||
{
|
|
||||||
return date_format($this->createdAt, "ymd");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCreatedAtTodayNoSeconds(): self
|
public function setCreatedAtTodayNoSeconds(): self
|
||||||
{
|
{
|
||||||
$this->setCreatedAt(DateTime::createFromFormat('Y-m-d H:i', date('Y-m-d H:i')));
|
$this->setCreatedAt(DateTime::createFromFormat('Y-m-d H:i', date('Y-m-d H:i')));
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Repository;
|
namespace App\Repository;
|
||||||
|
|
||||||
use App\Entity\Snip;
|
use App\Entity\Snip;
|
||||||
|
use App\Entity\User;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
@ -38,4 +39,14 @@ class SnipRepository extends ServiceEntityRepository
|
|||||||
$this->getEntityManager()->flush();
|
$this->getEntityManager()->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findByUser(User $user): array
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('s');
|
||||||
|
$qb->where('s.createdBy = :user')
|
||||||
|
->setParameter('user', $user)
|
||||||
|
->orderBy('s.createdAt', 'DESC');
|
||||||
|
|
||||||
|
return $qb->getQuery()->getResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
55
src/Service/SnipService.php
Normal file
55
src/Service/SnipService.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\Snip;
|
||||||
|
use App\Entity\User;
|
||||||
|
use CzProject\GitPhp\Git;
|
||||||
|
use CzProject\GitPhp\GitRepository;
|
||||||
|
|
||||||
|
class SnipService
|
||||||
|
{
|
||||||
|
private GitRepository $repo;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
Snip $snip,
|
||||||
|
string $snipBasePath,
|
||||||
|
private readonly User $user,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$git = new Git();
|
||||||
|
$repoPath = sprintf('%s/%s', $snipBasePath, $snip->getId());
|
||||||
|
if (!is_dir($repoPath)) {
|
||||||
|
$this->repo = $git->init($repoPath);
|
||||||
|
} else {
|
||||||
|
$this->repo = $git->open($repoPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function snipExists(): bool
|
||||||
|
{
|
||||||
|
return file_exists($this->getSnipPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSnipPath(): string
|
||||||
|
{
|
||||||
|
return sprintf('%s/snip.txt', $this->repo->getRepositoryPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(string $snipContents): void
|
||||||
|
{
|
||||||
|
file_put_contents($this->getSnipPath(), $snipContents);
|
||||||
|
$this->repo->addFile('snip.txt');
|
||||||
|
if ($this->repo->hasChanges()) {
|
||||||
|
$this->repo->commit(sprintf('Updated snip at %s by %s', date('Y-m-d H:i:s'), $this->user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(): string
|
||||||
|
{
|
||||||
|
if (!$this->snipExists()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return file_get_contents($this->getSnipPath());
|
||||||
|
}
|
||||||
|
}
|
22
src/Service/SnipServiceFactory.php
Normal file
22
src/Service/SnipServiceFactory.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\Snip;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
|
||||||
|
class SnipServiceFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly string $snipBasePath,
|
||||||
|
private readonly Security $security,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(Snip $snip): SnipService
|
||||||
|
{
|
||||||
|
return new SnipService($snip, $this->snipBasePath, $this->security->getUser());
|
||||||
|
}
|
||||||
|
}
|
@ -3,13 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{% block title %}BLES{% endblock %}</title>
|
<title>{% block title %}SNIPS{% endblock %}</title>
|
||||||
<link rel="shortcut icon" type="image/jpg" href="/favicon.png">
|
<link rel="shortcut icon" type="image/jpg" href="/favicon.png">
|
||||||
<script src="https://kit.fontawesome.com/3471b6556e.js" crossorigin="anonymous"></script>
|
|
||||||
{% if chartjs|default(false) %}
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@2.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
@ -59,6 +54,7 @@
|
|||||||
|
|
||||||
{# javascript block #}
|
{# javascript block #}
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
<script src="https://kit.fontawesome.com/3471b6556e.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"
|
||||||
integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13"
|
integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{% extends 'base/base.html.twig' %}
|
{% extends 'base/base.html.twig' %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h2>{{ snip }}</h2>
|
<h2>Editing {{ snip }}</h2>
|
||||||
{{ form(form) }}
|
{{ form(form) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -5,7 +5,7 @@
|
|||||||
<a class="btn btn-primary" href="{{ path('snip_new') }}">Create a new Snip</a>
|
<a class="btn btn-primary" href="{{ path('snip_new') }}">Create a new Snip</a>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for snip in snips %}
|
{% for snip in snips %}
|
||||||
<a class="list-group-item" href="{{ path('snip_edit', {snip: snip.id}) }}">
|
<a class="list-group-item" href="{{ path('snip_single', {snip: snip.id}) }}">
|
||||||
{{ snip }}
|
{{ snip }}
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
{% extends 'base/base.html.twig' %}
|
{% extends 'base/base.html.twig' %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1>{{ snip }}</h1>
|
<div class="card" style="width: 100%;">
|
||||||
|
<h4 class="card-header">
|
||||||
|
<a class="btn btn-sm btn-outline-info" href="{{ path('snip_edit', {snip: snip.id}) }}">
|
||||||
|
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{{ snip }}
|
||||||
|
</h4>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="card-text">{{ content }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user