@denlem
Programmer

Как грамотно улучшить свой сервис на Symfony в плане ООП подхода?

Здравствуйте. Я начинаю изучать 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 не публикую - там обычная доктриновская сущность без каких то особенностей
  • Вопрос задан
  • 576 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы