Здравствуйте. Я начинаю изучать Symfony и ООП. Написал свой небольшой тестовый проект. Но чувствуется что там присутствует г###код.
Помогите/порекомендуйте как поменять его, что исправить, чтобы было грамотно с позиции ООП подхода.
Суть сервиса: Парсинг-сбор новостей с новостного сайта и погружение их в базу данных, а также вывод списка новостей. Основной вопрос в грамотности структуры сервиса в аспекте ООП подхода
Класс контроллер PostController :
use App\Entity\Post;
use Doctrine\ORM\EntityManagerInterface;
use PHPHtmlParser\Dom;
use GuzzleHttp\Client;
class PostController extends AbstractController
{
private $postRepository;
public function __construct(PostRepository $postRepository)
{
$this->postRepository = $postRepository;
}
/**
* @Route("/", name="posts")
*/
public function index(Request $request, RbcParseClient $parse): Response
{
if ($request->query->get('update') && $request->query->get('update') == '1'){
$parse->updateNews();
}
$posts = $this->postRepository->findLastNews();
return $this->render('post/posts.html.twig', [
'posts' => $posts
]);
}
}
Основной класс сервиса RbcParseClient к которому идет запрос для сбора и парсинга новостей (сейчас запрос из контроллера, но это не принципиально, можно сделать и из крон файла) :
use App\Entity\Post;
use Doctrine\ORM\EntityManagerInterface;
use PHPHtmlParser\Dom;
use GuzzleHttp\Client;
class RbcParseClient
{
private $dom;
private $em;
private $checkPosts;
public function __construct(EntityManagerInterface $em)
{
$this->dom = new Dom();
$this->em = $em;
$postRepository = $this->em->getRepository(Post::class);
$this->checkPosts = $postRepository->findLastNews();
}
public function updateNews(): void
{
$res = self::getUrlContent('https://www.rbc.ru');
$this->dom->load($res);
$contents = $this->dom->find('.news-feed__wrapper .js-news-feed-list')->find('a.news-feed__item');
foreach ($contents as $content)
{
$link = $content->getAttribute('href');
$resDomContent = self::getUrlContent($link);
$this->dom->load($resDomContent);
if (preg_match("/style.rbc/", $link) ) {
$currentNewsItem = new StyleItem($this->dom, $link);
}elseif(preg_match("/agrodigital.rbc/", $link)){
$currentNewsItem = new AgroItem($this->dom, $link);
}else {
$currentNewsItem = new RegularItem($this->dom, $link);
}
$currentNewsItem->parseNewsItem();
$date = self::getItemDate($content);
$currentNewsItem->setDate($date);
$post = new Post();
$position = $date->format('U');
$post->setTitle($currentNewsItem->getTitle());
$post->setBody($currentNewsItem->getBody());
$post->setImage($currentNewsItem->getImage());
$post->setLink($currentNewsItem->getLink());
$post->setCreatedAt($date);
$post->setPosition($position);
$this->em->persist($post);
}
$this->em->flush();
}
public static function getItemDate(Dom\HtmlNode $content): \DateTime
{
$dateInfo = $content
->find('.news-feed__item__date .news-feed__item__date-text')->innerHTML;
$time = explode(" ", $dateInfo)[1];
$date = new \DateTime("now");
$timeSet = explode(":",$time);
$date->setTime((int)$timeSet[0], (int)$timeSet[1]);
return $date;
}
public static function getUrlContent(string $url): string
{
$client = new Client([ 'base_uri' => $url ]);
$response = $client->request('GET');
$res = $response->getBody();
return $res;
}
}
Вспомогательные классы сервиса RegularItem, StyleItem, AgroItem и т д. Тут пример одного класса RegularItem. Остальные имеют небольшие отличия в зависимости от особенностей парсинга:
use PHPHtmlParser\Dom;
class RegularItem extends AbstractParseManager
{
public function parseNewsItem(): void
{
if ($this->dom->find(".js-rbcslider")[0]) {
$this->parseTitle();
$this->parseImg();
$this->parseContent();
}else{
$this->title = $this->image = $this->body = "";
}
}
private function parseTitle(): void
{
try {
$artTitle = $this->dom->find(".js-rbcslider")[0]->find('.article__header .article__header__title .js-slide-title')->innerHtml;
$this->title = $artTitle;
}catch(\Exception $e){
$this->title = "";
}
}
private function parseImg(){
try {
$artImg = $this->dom->find(".js-rbcslider")[0]->find('.article__text .article__main-image img');
$this->image = $artImg->getAttribute('src');
}catch(\Exception $e){
$this->image = "";
}
}
private function parseContent(){
try {
$artContents = $this->dom->find(".js-rbcslider")[0]->find('.article .article__text');
$html = "";
$domContent = new Dom();
foreach ($artContents as $content)
{
$domContent->load($content);
$artStrings = $domContent->find("p");
foreach ($artStrings as $string) {
$str = strip_tags($string->innerHtml);
$html .= "<br />" . trim($str);
}
}
$this->body = $html;
}catch(\Exception $e){
$this->body = "";
}
}
}
Абстрактный класс менеджер AbstractParseManager:
use PHPHtmlParser\Dom;
abstract class AbstractParseManager
{
protected $title;
protected $image;
protected $body;
protected $link;
protected $date;
protected $dom;
public function __construct(Dom $dom, string $link)
{
$this->link = $link;
$this->dom = $dom;
}
abstract public function parseNewsItem(): void ;
public function getTitle()
{
return $this->title;
}
public function getBody()
{
return $this->body;
}
public function getImage()
{
return $this->image;
}
public function getLink()
{
return $this->link;
}
public function getDate()
{
return $this->date;
}
public function setDate(\DateTime $date): void
{
$this->date = $date;
}
}
Класс репозиторий:
use App\Entity\Post;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
class PostRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Post::class);
}
public function findLastNews()
{
return $this->createQueryBuilder('p')
->orderBy('p.position', 'DESC')
->setMaxResults(15)
->getQuery()
->getResult()
;
}
}
Класс сущности Post не публикую - там обычная доктриновская сущность без каких то особенностей