[CONTROLLER][Feeds] Implement query for home feed: note-from:subscribed
This commit is contained in:
parent
e3efd25b43
commit
dabf5576d3
@ -25,6 +25,7 @@ use App\Core\Cache;
|
|||||||
use App\Core\Event;
|
use App\Core\Event;
|
||||||
use App\Core\Modules\Component;
|
use App\Core\Modules\Component;
|
||||||
use App\Core\Router\RouteLoader;
|
use App\Core\Router\RouteLoader;
|
||||||
|
use App\Entity\Actor;
|
||||||
use App\Entity\Note;
|
use App\Entity\Note;
|
||||||
use App\Util\Formatting;
|
use App\Util\Formatting;
|
||||||
use Component\Attachment\Controller as C;
|
use Component\Attachment\Controller as C;
|
||||||
@ -74,7 +75,7 @@ class Attachment extends Component
|
|||||||
/**
|
/**
|
||||||
* Populate $note_expr with the criteria for looking for notes with attachments
|
* Populate $note_expr with the criteria for looking for notes with attachments
|
||||||
*/
|
*/
|
||||||
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool
|
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr)
|
||||||
{
|
{
|
||||||
$include_term = str_contains($term, ':') ? explode(':', $term)[1] : $term;
|
$include_term = str_contains($term, ':') ? explode(':', $term)[1] : $term;
|
||||||
if (Formatting::startsWith($term, ['note-types:', 'notes-incude:', 'note-filter:'])) {
|
if (Formatting::startsWith($term, ['note-types:', 'notes-incude:', 'note-filter:'])) {
|
||||||
|
@ -27,18 +27,21 @@ use App\Core\DB\DB;
|
|||||||
use App\Core\Event;
|
use App\Core\Event;
|
||||||
use App\Core\Modules\Component;
|
use App\Core\Modules\Component;
|
||||||
use App\Entity\Actor;
|
use App\Entity\Actor;
|
||||||
|
use App\Entity\Subscription;
|
||||||
use App\Util\Formatting;
|
use App\Util\Formatting;
|
||||||
use Component\Search\Util\Parser;
|
use Component\Search\Util\Parser;
|
||||||
use Doctrine\Common\Collections\ExpressionBuilder;
|
use Doctrine\Common\Collections\ExpressionBuilder;
|
||||||
|
use Doctrine\ORM\Query\Expr;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
|
||||||
class Feed extends Component
|
class Feed extends Component
|
||||||
{
|
{
|
||||||
public static function query(string $query, int $page, ?string $language = null): array
|
public static function query(string $query, int $page, ?string $language = null, ?Actor $actor = null): array
|
||||||
{
|
{
|
||||||
$note_criteria = null;
|
$note_criteria = null;
|
||||||
$actor_criteria = null;
|
$actor_criteria = null;
|
||||||
if (!empty($query = trim($query))) {
|
if (!empty($query = trim($query))) {
|
||||||
[$note_criteria, $actor_criteria] = Parser::parse($query, $language);
|
[$note_criteria, $actor_criteria] = Parser::parse($query, $language, $actor);
|
||||||
}
|
}
|
||||||
$note_qb = DB::createQueryBuilder();
|
$note_qb = DB::createQueryBuilder();
|
||||||
$actor_qb = DB::createQueryBuilder();
|
$actor_qb = DB::createQueryBuilder();
|
||||||
@ -62,34 +65,45 @@ class Feed extends Component
|
|||||||
return ['notes' => $notes ?? null, 'actors' => $actors ?? null];
|
return ['notes' => $notes ?? null, 'actors' => $actors ?? null];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onSearchQueryAddJoins(QueryBuilder &$note_qb, QueryBuilder &$actor_qb)
|
||||||
|
{
|
||||||
|
$note_qb->leftJoin(Subscription::class, 'subscription', Expr\Join::WITH, 'note.actor_id = subscription.subscribed');
|
||||||
|
return Event::next;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert $term to $note_expr and $actor_expr, search criteria. Handles searching for text
|
* Convert $term to $note_expr and $actor_expr, search criteria. Handles searching for text
|
||||||
* notes, for different types of actors and for the content of text notes
|
* notes, for different types of actors and for the content of text notes
|
||||||
*/
|
*/
|
||||||
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool
|
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr)
|
||||||
{
|
{
|
||||||
if (str_contains($term, ':')) {
|
if (str_contains($term, ':')) {
|
||||||
$term = explode(':', $term);
|
$term = explode(':', $term);
|
||||||
if (Formatting::startsWith($term[0], 'note-')) {
|
if (Formatting::startsWith($term[0], 'note-')) {
|
||||||
switch ($term[0]) {
|
switch ($term[0]) {
|
||||||
case 'note-local':
|
case 'note-local':
|
||||||
$note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN));
|
$note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN));
|
||||||
break;
|
break;
|
||||||
case 'note-types':
|
case 'note-types':
|
||||||
case 'notes-include':
|
case 'notes-include':
|
||||||
case 'note-filter':
|
case 'note-filter':
|
||||||
if (\is_null($note_expr)) {
|
if (\is_null($note_expr)) {
|
||||||
$note_expr = [];
|
$note_expr = [];
|
||||||
}
|
}
|
||||||
if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) {
|
if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) {
|
||||||
$note_expr[] = $eb->neq('note.content', null);
|
$note_expr[] = $eb->neq('note.content', null);
|
||||||
} else {
|
} else {
|
||||||
$note_expr[] = $eb->eq('note.content', null);
|
$note_expr[] = $eb->eq('note.content', null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'note-conversation':
|
case 'note-conversation':
|
||||||
$note_expr = $eb->eq('note.conversation_id', (int)trim($term[1]));
|
$note_expr = $eb->eq('note.conversation_id', (int) trim($term[1]));
|
||||||
break;
|
break;
|
||||||
|
case 'note-from':
|
||||||
|
if ($term[1] === 'subscribed') {
|
||||||
|
$note_expr = $eb->eq('subscription.subscriber', $actor->getId());
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} elseif (Formatting::startsWith($term, 'actor-')) {
|
} elseif (Formatting::startsWith($term, 'actor-')) {
|
||||||
switch ($term[0]) {
|
switch ($term[0]) {
|
||||||
|
@ -31,10 +31,10 @@ use App\Util\Formatting;
|
|||||||
use App\Util\Functional as GSF;
|
use App\Util\Functional as GSF;
|
||||||
use Component\Language\Controller as C;
|
use Component\Language\Controller as C;
|
||||||
use Doctrine\Common\Collections\ExpressionBuilder;
|
use Doctrine\Common\Collections\ExpressionBuilder;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Doctrine\ORM\Query\Expr;
|
use Doctrine\ORM\Query\Expr;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Functional as F;
|
use Functional as F;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
class Language extends Component
|
class Language extends Component
|
||||||
{
|
{
|
||||||
@ -46,7 +46,9 @@ class Language extends Component
|
|||||||
|
|
||||||
public function onFilterNoteList(?Actor $actor, array &$notes, Request $request)
|
public function onFilterNoteList(?Actor $actor, array &$notes, Request $request)
|
||||||
{
|
{
|
||||||
if (\is_null($actor)) return Event::next;
|
if (\is_null($actor)) {
|
||||||
|
return Event::next;
|
||||||
|
}
|
||||||
$notes = F\select(
|
$notes = F\select(
|
||||||
$notes,
|
$notes,
|
||||||
fn (Note $n) => \in_array($n->getLanguageId(), ActorLanguage::getActorRelatedLanguagesIds($actor)),
|
fn (Note $n) => \in_array($n->getLanguageId(), ActorLanguage::getActorRelatedLanguagesIds($actor)),
|
||||||
@ -58,7 +60,7 @@ class Language extends Component
|
|||||||
/**
|
/**
|
||||||
* Populate $note_expr or $actor_expr with an expression to match a language
|
* Populate $note_expr or $actor_expr with an expression to match a language
|
||||||
*/
|
*/
|
||||||
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool
|
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr)
|
||||||
{
|
{
|
||||||
$search_term = str_contains($term, ':') ? explode(':', $term)[1] : $term;
|
$search_term = str_contains($term, ':') ? explode(':', $term)[1] : $term;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ declare(strict_types = 1);
|
|||||||
namespace Component\Search\Util;
|
namespace Component\Search\Util;
|
||||||
|
|
||||||
use App\Core\Event;
|
use App\Core\Event;
|
||||||
|
use App\Entity\Actor;
|
||||||
use App\Util\Exception\ServerException;
|
use App\Util\Exception\ServerException;
|
||||||
use Doctrine\Common\Collections\Criteria;
|
use Doctrine\Common\Collections\Criteria;
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ abstract class Parser
|
|||||||
*
|
*
|
||||||
* @return Criteria[]
|
* @return Criteria[]
|
||||||
*/
|
*/
|
||||||
public static function parse(string $input, ?string $language = null, int $level = 0): array
|
public static function parse(string $input, ?string $language = null, ?Actor $actor = null, int $level = 0): array
|
||||||
{
|
{
|
||||||
if ($level === 0) {
|
if ($level === 0) {
|
||||||
$input = trim(preg_replace(['/\s+/', '/\s+AND\s+/', '/\s+OR\s+/'], [' ', '&', '|'], $input), ' |&');
|
$input = trim(preg_replace(['/\s+/', '/\s+AND\s+/', '/\s+OR\s+/'], [' ', '&', '|'], $input), ' |&');
|
||||||
@ -77,7 +78,7 @@ abstract class Parser
|
|||||||
$term = mb_substr($input, $left, $end ? null : $right - $left);
|
$term = mb_substr($input, $left, $end ? null : $right - $left);
|
||||||
$note_res = null;
|
$note_res = null;
|
||||||
$actor_res = null;
|
$actor_res = null;
|
||||||
Event::handle('SearchCreateExpression', [$eb, $term, $language, &$note_res, &$actor_res]);
|
Event::handle('SearchCreateExpression', [$eb, $term, $language, $actor, &$note_res, &$actor_res]);
|
||||||
if (\is_null($note_res) && \is_null($actor_res)) {
|
if (\is_null($note_res) && \is_null($actor_res)) {
|
||||||
throw new ServerException("No one claimed responsibility for a match term: {$term}");
|
throw new ServerException("No one claimed responsibility for a match term: {$term}");
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ class Tag extends Component
|
|||||||
*
|
*
|
||||||
* $term /^(note|tag|people|actor)/ means we want to match only either a note or an actor
|
* $term /^(note|tag|people|actor)/ means we want to match only either a note or an actor
|
||||||
*/
|
*/
|
||||||
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool
|
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr)
|
||||||
{
|
{
|
||||||
$search_term = str_contains($term, ':#') ? explode(':', $term)[1] : $term;
|
$search_term = str_contains($term, ':#') ? explode(':', $term)[1] : $term;
|
||||||
$canon_search_term = self::canonicalTag($search_term, $language);
|
$canon_search_term = self::canonicalTag($search_term, $language);
|
||||||
|
@ -74,9 +74,10 @@ class Feeds extends FeedController
|
|||||||
public function home(Request $request): array
|
public function home(Request $request): array
|
||||||
{
|
{
|
||||||
$data = Feed::query(
|
$data = Feed::query(
|
||||||
query: 'from:subscribed-actors OR from:subscribed-groups',
|
query: 'note-from:subscribed',
|
||||||
page: $this->int('p'),
|
page: $this->int('p'),
|
||||||
language: Common::actor()?->getTopLanguage()?->getLocale(),
|
language: Common::actor()?->getTopLanguage()?->getLocale(),
|
||||||
|
actor: Common::actor(),
|
||||||
);
|
);
|
||||||
return [
|
return [
|
||||||
'_template' => 'feed/feed.html.twig',
|
'_template' => 'feed/feed.html.twig',
|
||||||
|
Loading…
Reference in New Issue
Block a user