Torrent search and torrent show implemented. Simple imdex page implemented.

This commit is contained in:
Alexey Skobkin 2018-06-21 02:37:35 +03:00
parent b409bfbfc7
commit 8ab6acf620
14 changed files with 202 additions and 97 deletions

View File

@ -0,0 +1,2 @@
white_october_pagerfanta:
default_view: twitter_bootstrap4

View File

@ -1,7 +1,16 @@
#index:
# path: /
# controller: App\Controller\DefaultController::index
test:
index:
path: /
controller: App\Controller\TestController::test
controller: App\Controller\MainController::index
torrent_show:
path: /torrents/{id}
controller: App\Controller\TorrentController::showTorrent
requirements:
method: GET
id: '\d+'
torrent_search:
path: /torrents/search
controller: App\Controller\TorrentController::searchTorrent
requirements:
method: GET

View File

@ -0,0 +1,3 @@
#content {
margin-top: 80px;
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Controller;
use App\Repository\TorrentRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MainController extends Controller
{
public function index(TorrentRepository $repo)
{
return $this->render('index.html.twig', [
'torrentsCount' => $repo->getTorrentsTotalCount(),
]);
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class TestController extends Controller
{
public function test(\App\Repository\Torrent $torrentRepo)
{
$torrents = $torrentRepo->getLastTorrents(10);
return $this->render('torrent_list.html.twig', [
'torrents' => $torrents,
]);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Controller;
use App\Entity\Torrent;
use App\Repository\TorrentRepository;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Pagerfanta\Pagerfanta;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class TorrentController extends Controller
{
private const PER_PAGE = 20;
public function showTorrent(Torrent $torrent)
{
return $this->render('torrent_show.html.twig', [
'torrent' => $torrent,
]);
}
public function searchTorrent(Request $request, TorrentRepository $repo)
{
$query = $request->query->get('query', '');
$page = (int) $request->query->get('page', '1');
$pagerAdapter = new DoctrineORMAdapter($repo->createFindLikeQueryBuilder($query));
$pager = new Pagerfanta($pagerAdapter);
$pager
->setCurrentPage($page)
->setMaxPerPage(self::PER_PAGE)
;
return $this->render('search_results.html.twig', [
'torrents' => $pager,
'searchQuery' => $query,
]);
}
}

View File

@ -10,7 +10,7 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Index(name="discovered_on_index", columns={"discovered_on"}),
* @ORM\Index(name="info_hash_index", columns={"info_hash"})
* })
* @ORM\Entity(readOnly=true)
* @ORM\Entity(readOnly=true, repositoryClass="App\Repository\TorrentRepository")
*/
class Torrent
{
@ -67,7 +67,7 @@ class Torrent
return $this->infoHash;
}
public function getInfoHashAsHex()
public function getInfoHashAsHex(): string
{
return bin2hex(stream_get_contents($this->infoHash));
}

View File

@ -1,24 +0,0 @@
<?php
namespace App\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
class Torrent extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, \App\Entity\Torrent::class);
}
public function getLastTorrents(int $number): array
{
$qb = $this->createQueryBuilder('t')
->orderBy('t.discoveredOn', 'DESC')
->setMaxResults($number)
;
return $qb->getQuery()->getResult();
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\RegistryInterface;
class TorrentRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, \App\Entity\Torrent::class);
}
public function getTorrentsTotalCount(): int
{
$qb = $this->createQueryBuilder('t')
->select('COUNT(t.id)')
;
return (int) $qb->getQuery()->getSingleScalarResult();
}
public function createFindLikeQueryBuilder(string $query): QueryBuilder
{
$qb = $this->createQueryBuilder('t');
$where = $qb->expr()->andX();
$query = trim($query);
$query = preg_replace('/\s+/', ' ', $query);
$parts = explode(' ', $query);
foreach ($parts as $idx => $part) {
$where->add($qb->expr()->like('LOWER(t.name)', ':part_'.$idx));
$qb->setParameter('part_'.$idx, '%'.strtolower($part).'%');
}
$qb->where($where);
return $qb;
}
}

View File

@ -7,63 +7,41 @@
<meta name="description" content="">
<meta name="author" content="">
{% endblock %}
<!--<link rel="icon" href="images/favicon.ico">-->
<!--<link rel="icon" href="/images/favicon.ico">-->
<title>{% block title %}Magnetoco Web{% endblock %}</title>
{% block css %}
<!-- Bootstrap core CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<!--<link href="starter-template.css" rel="stylesheet">-->
<link href="/css/style.css" rel="stylesheet">
{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="#">Navbar</a>
<a class="navbar-brand" href="{{ path('index') }}">Magnetico Web</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="https://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
{% block navbar_menu_items %}
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
{% endblock %}
</div>
<a class="nav-link" href="#">Last</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<form class="form-inline my-2 my-lg-0" action="{{ path('torrent_search') }}" method="get">
<input name="query" class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search"
value="{% if searchQuery is defined %}{{ searchQuery }}{% endif %}">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container">
{% block content %}
<div class="well">
<h1>Bootstrap starter template</h1>
<p class="lead">Use this document as a way to quickly start any new project.<br> All you get is this text and a mostly barebones HTML document.</p>
</div>
{% endblock %}
<main id="content" role="main" class="container">
{% block content %}{% endblock %}
</main><!-- /.container -->
{% block javascript %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html.twig' %}
{% block content %}
<div class="well">
<p>Torrents indexed: {{ torrentsCount }}</p>
</div>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'base.html.twig' %}
{% block content %}
{% include 'torrent_list.html.twig' with {'torrents': torrents} %}
{% endblock %}

View File

@ -1,33 +1,32 @@
{% extends 'base.html.twig' %}
{% block content %}
<div class="pagination">
{{ pagerfanta(torrents) }}
</div>
<table class="table">
<thead>
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Size</th>
<th scope="col">Discovered</th>
<th scope="col">Files</th>
<th scope="col">Link</th>
</thead>
{# @var torrent \App\Entity\\App\Entity\Torrent #}
{# @var torrent \App\Entity\Torrent #}
{% for torrent in torrents %}
<tr>
<td>{{ torrent.id }}</td>
<td>
<a href="magnet:?xt=urn:btih:{{ torrent.infoHashAsHex }}&dn={{ torrent.name|url_encode }}">{{ torrent.name }}</a>
<a href="{{ path('torrent_show', {'id': torrent.id}) }}">{{ torrent.name }}</a>
</td>
<td>{{ torrent.totalSize }}</td>
<td>{{ torrent.discoveredOn }}</td>
<td>{{ (torrent.totalSize / 1024 / 1024) | round(2, 'ceil')}} MB</td>
<td>{{ torrent.discoveredOn | date('Y-m-d H:i:s')}}</td>
<td>
{#
<ul>
{% for file in torrent.files %}
<li>{{ file.path }}</li>
{% endfor %}
</ul>
#}
<a href="magnet:?xt=urn:btih:{{ torrent.infoHashAsHex }}&dn={{ torrent.name | url_encode }}">&#128279;</a>
</td>
</tr>
{% endfor %}
</table>
<div class="pagination">
{{ pagerfanta(torrents) }}
</div>
{% endblock %}

View File

@ -0,0 +1,43 @@
{% extends 'base.html.twig' %}
{% block content %}
{# @var torrent \App\Entity\Torrent #}
<table class="table">
<tr>
<td>Name</td>
<td>{{ torrent.name }}</td>
</tr>
<tr>
<td>Hash</td>
<td>
<a href="magnet:?xt=urn:btih:{{ torrent.infoHashAsHex }}&dn={{ torrent.name | url_encode }}">{{ torrent.infoHashAsHex }}</a>
</td>
</tr>
<tr>
<td>Size</td>
<td>{{ (torrent.totalSize / 1024 / 1024) | round(2, 'ceil')}} MB</td>
</tr>
<tr>
<td>Discovered</td>
<td>{{ torrent.discoveredOn | date('Y-m-d H:i:s')}}</td>
</tr>
</table>
<table class="table">
<thead>
<tr>
<th scope="col">File</th>
<th scope="col">Size</th>
</tr>
</thead>
<tbody>
{# @var file \App\Entity\File #}
{% for file in torrent.files | sort %}
<tr>
<td>{{ file.path }}</td>
<td>{{ (file.size / 1024 / 1024) | round(2, 'ceil')}} MB</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}