[NETWORK][TreeNotes] Add TreeNotes plugin which takes over the responsibility of displaying a conversation as a tree, in order to reduce the number of queries
This commit is contained in:
		
							
								
								
									
										52
									
								
								plugins/TreeNotes/TreeNotes.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								plugins/TreeNotes/TreeNotes.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| <?php | ||||
|  | ||||
| // {{{ License | ||||
| // This file is part of GNU social - https://www.gnu.org/software/social | ||||
| // | ||||
| // GNU social is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU Affero General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // GNU social is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU Affero General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU Affero General Public License | ||||
| // along with GNU social.  If not, see <http://www.gnu.org/licenses/>. | ||||
| // }}} | ||||
|  | ||||
| namespace Plugin\TreeNotes; | ||||
|  | ||||
| use App\Entity\Note; | ||||
| use App\Core\Event; | ||||
| use App\Core\Module; | ||||
| use Functional as F; | ||||
|  | ||||
| class TreeNotes extends Module | ||||
| { | ||||
|     /** | ||||
|      * Format the given $notes_in_trees_out in a list of reply trees | ||||
|      */ | ||||
|     public function onFormatNoteList(array &$notes_in_trees_out) | ||||
|     { | ||||
|         $roots = array_filter($notes_in_trees_out, function(Note $note) { return $note->getReplyTo() == null; }, ARRAY_FILTER_USE_BOTH); | ||||
|         $notes_in_trees_out = $this->build_tree($roots, $notes_in_trees_out); | ||||
|     } | ||||
|  | ||||
|     private function build_tree(array $parents, array $notes) | ||||
|     { | ||||
|         $subtree = []; | ||||
|         foreach ($parents as $p) { | ||||
|             $subtree[] = $this->build_subtree($p, $notes); | ||||
|         } | ||||
|         return $subtree; | ||||
|     } | ||||
|  | ||||
|     private function build_subtree(Note $parent, array $notes) | ||||
|     { | ||||
|         $children = array_filter($notes, function(Note $n) use ($parent) { return $parent->getId() == $n->getReplyTo(); }, ARRAY_FILTER_USE_BOTH); | ||||
|         return ['note' => $parent, 'replies' => $this->build_tree($children, $notes)]; | ||||
|     } | ||||
| } | ||||
| @@ -35,10 +35,11 @@ namespace App\Controller; | ||||
|  | ||||
| use App\Core\Controller; | ||||
| use App\Core\DB\DB; | ||||
| use function App\Core\I18n\_m; | ||||
| use App\Core\Event; | ||||
| use App\Core\NoteScope; | ||||
| use App\Util\Common; | ||||
| use App\Util\Exception\ClientException; | ||||
| use function App\Core\I18n\_m; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
|  | ||||
| class Network extends Controller | ||||
| @@ -51,12 +52,16 @@ class Network extends Controller | ||||
|  | ||||
|     public function public(Request $request) | ||||
|     { | ||||
|         $notes = DB::sql('select * from note n ' . | ||||
|                          "where (n.scope & {$this->instance_scope}) <> 0 " . | ||||
|                          'order by n.created DESC', | ||||
|                          ['n' => 'App\Entity\Note']); | ||||
|  | ||||
|         Event::handle('FormatNoteList', [&$notes]); | ||||
|  | ||||
|         return [ | ||||
|             '_template' => 'network/public.html.twig', | ||||
|             'notes'     => DB::sql('select * from note n ' . | ||||
|                                    "where n.reply_to is null and (n.scope & {$this->instance_scope}) <> 0 " . | ||||
|                                    'order by n.created DESC', | ||||
|                                    ['n' => 'App\Entity\Note']), | ||||
|             'notes'     => $notes, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -90,9 +90,8 @@ | ||||
|                 <div class="timeline"> | ||||
|                     <div class="notes"> | ||||
|                         {% if notes is defined and notes is not empty %} | ||||
|                             {% for note in notes %} | ||||
|                               {% set id = note.getId() - 1 %} | ||||
|                               {% include '/note/view.html.twig' with {'note': note, 'have_user': have_user} only %} | ||||
|                             {% for conversation in notes %} | ||||
|                               {% include '/note/view.html.twig' with {'note': conversation['note'], 'have_user': have_user, 'replies': conversation['replies']} only %} | ||||
|                             {% endfor %} | ||||
|                         {% else %} | ||||
|                             <h1>{% trans %}No notes here.{% endtrans %}</h1> | ||||
|   | ||||
| @@ -42,8 +42,8 @@ | ||||
|     {% endif %} | ||||
|   </div> | ||||
|   <div class="replies"> | ||||
|     {% for reply in note.getReplies() %} | ||||
|       {% include '/note/view.html.twig' with {'note': reply, 'skip_reply_to': true, 'have_user': have_user} only %} | ||||
|     {% for conversation in replies %} | ||||
|       {% include '/note/view.html.twig' with {'note': conversation['note'], 'skip_reply_to': true, 'have_user': have_user, 'replies': conversation['replies']} only %} | ||||
|     {% endfor %} | ||||
|   </div> | ||||
| </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user