diff --git a/components/Language/Controller/Language.php b/components/Language/Controller/Language.php new file mode 100644 index 0000000000..4304ce1fdd --- /dev/null +++ b/components/Language/Controller/Language.php @@ -0,0 +1,146 @@ +. + +// }}} + +namespace Component\Language\Controller; + +use App\Core\Cache; +use App\Core\Controller; +use App\Core\DB\DB; +use App\Core\Form; +use function App\Core\I18n\_m; +use App\Entity\ActorLanguage; +use App\Entity\Language as LangEntity; +use App\Util\Common; +use App\Util\Exception\NoLoggedInUser; +use App\Util\Exception\RedirectException; +use App\Util\Exception\ServerException; +use App\Util\Form\FormFields; +use Functional as F; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\SubmitButton; +use Symfony\Component\HttpFoundation\Request; + +class Language extends Controller +{ + /** + * @throws NoLoggedInUser + * @throws RedirectException + * @throws ServerException + */ + public function settings(Request $request): FormInterface + { + $user = Common::ensureLoggedIn(); + // TODO Add support missing settings + + $form = Form::create([ + FormFields::language($user->getActor(), context_actor: null, label: _m('Languages'), help: _m('The languages you understand, so you can see primarily content in those'), multiple: true, required: false, use_short_display: false), + ['save_languages', SubmitType::class, ['label' => _m('Proceed to order selected languages')]], + ]); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $data = $form->getData(); + + if (!\is_null($data['languages'])) { + $selected_langs = DB::findBy('language', ['locale' => $data['languages']]); + $existing_langs = DB::dql( + 'select l from language l join actor_language al with l.id = al.language_id where al.actor_id = :actor_id', + ['actor_id' => $user->getId()], + ); + + $new_langs = array_udiff($selected_langs, $existing_langs, fn ($l, $r) => $l->getId() <=> $r->getId()); + $removing_langs = array_udiff($existing_langs, $selected_langs, fn ($l, $r) => $l->getId() <=> $r->getId()); + foreach ($new_langs as $l) { + DB::persist(ActorLanguage::create(['actor_id' => $user->getId(), 'language_id' => $l->getId(), 'ordering' => 0])); + } + + if (!empty($removing_langs)) { + $actor_langs_to_remove = DB::findBy('actor_language', ['actor_id' => $user->getId(), 'language_id' => F\map($removing_langs, fn ($l) => $l->getId())]); + foreach ($actor_langs_to_remove as $lang) { + DB::remove($lang); + } + } + + Cache::delete(ActorLanguage::cacheKeys($user)['actor-langs']); + ActorLanguage::normalizeOrdering($user); // In case the user doesn't submit the other page + DB::flush(); + unset($data['languages']); + + throw new RedirectException('settings_sort_languages', ['_fragment' => null]); // TODO doesn't clear fragment + } + } + return $form; + } + + /** + * Controller for defining the ordering of a users' languages + * + * @throws NoLoggedInUser + * @throws RedirectException + * @throws ServerException + */ + public function sortLanguages(Request $request): array + { + $user = Common::ensureLoggedIn(); + + $langs = DB::dql('select l.locale, l.long_display, al.ordering from language l join actor_language al with l.id = al.language_id where al.actor_id = :id order by al.ordering ASC', ['id' => $user->getId()]); + + $form_entries = []; + foreach ($langs as $l) { + $form_entries[] = [$l['locale'], IntegerType::class, ['label' => _m($l['long_display']), 'data' => $l['ordering']]]; + } + + $form_entries[] = ['save_language_order', SubmitType::class, []]; + $form_entries[] = ['go_back', SubmitType::class, ['label' => _m('Return to settings page')]]; + $form = Form::create($form_entries); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + /** @var SubmitButton $button */ + $button = $form->get('go_back'); + $go_back = $button->isClicked(); + $data = $form->getData(); + asort($data); // Sort by the order value + $data = array_keys($data); // This keeps the order and gives us a unique number for each + foreach ($data as $order => $locale) { + $lang = LangEntity::getByLocale($locale); + $actor_lang = DB::getReference('actor_language', ['actor_id' => $user->getId(), 'language_id' => $lang->getId()]); + $actor_lang->setOrdering($order + 1); + } + DB::flush(); + if (!$go_back) { + // Stay on same page, but force update and prevent resubmission + throw new RedirectException('settings_sort_languages'); + } else { + throw new RedirectException('settings', ['open' => 'account', '_fragment' => 'save_account_info_languages']); + } + } + + return [ + '_template' => 'settings/sort_languages.html.twig', + 'form' => $form->createView(), + ]; + } +} diff --git a/components/Language/Language.php b/components/Language/Language.php index 599f8b0c39..c6e83d1cfa 100644 --- a/components/Language/Language.php +++ b/components/Language/Language.php @@ -23,11 +23,13 @@ namespace Component\Language; use App\Core\Event; use App\Core\Modules\Component; +use App\Core\Router\RouteLoader; use App\Entity\Actor; use App\Entity\ActorLanguage; use App\Entity\Note; use App\Util\Formatting; use App\Util\Functional as GSF; +use Component\Language\Controller as C; use Doctrine\Common\Collections\ExpressionBuilder; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query\Expr; @@ -36,6 +38,12 @@ use Functional as F; class Language extends Component { + public function onAddRoute(RouteLoader $r) + { + $r->connect('settings_sort_languages', '/settings/sort_languages', [C\Language::class, 'sortLanguages']); + return Event::next; + } + public function onFilterNoteList(?Actor $actor, array &$notes, Request $request) { if (\is_null($actor)) return Event::next; diff --git a/templates/settings/sort_languages.html.twig b/components/Language/templates/language/sort.html.twig similarity index 100% rename from templates/settings/sort_languages.html.twig rename to components/Language/templates/language/sort.html.twig diff --git a/src/Controller/UserPanel.php b/src/Controller/UserPanel.php index 8957bf7cda..f00ff53530 100644 --- a/src/Controller/UserPanel.php +++ b/src/Controller/UserPanel.php @@ -44,8 +44,6 @@ use App\Core\Event; use App\Core\Form; use function App\Core\I18n\_m; use App\Core\Log; -use App\Entity\ActorLanguage; -use App\Entity\Language; use App\Util\Common; use App\Util\Exception\AuthenticationException; use App\Util\Exception\NicknameEmptyException; @@ -54,25 +52,22 @@ use App\Util\Exception\NicknameNotAllowedException; use App\Util\Exception\NicknameTakenException; use App\Util\Exception\NicknameTooLongException; use App\Util\Exception\NoLoggedInUser; -use App\Util\Exception\RedirectException; use App\Util\Exception\ServerException; use App\Util\Form\ActorArrayTransformer; use App\Util\Form\ArrayTransformer; use App\Util\Form\FormFields; use App\Util\Formatting; +use Component\Language\Controller\Language as LanguageController; use Component\Notification\Entity\UserNotificationPrefs; use Doctrine\DBAL\Types\Types; use Exception; -use Functional as F; use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; -use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\SubmitButton; use Symfony\Component\HttpFoundation\Request; // }}} Imports @@ -84,12 +79,12 @@ class UserPanel extends Controller * * @throws Exception */ - public function allSettings(Request $request): array + public function allSettings(Request $request, LanguageController $language): array { $personal_form = $this->personalInfo($request); $email_form = $this->email($request); $password_form = $this->password($request); - $language_form = $this->language($request); + $language_form = $language->settings($request); $notifications_form_array = $this->notifications($request); @@ -176,56 +171,6 @@ class UserPanel extends Controller return $form; } - /** - * @throws NoLoggedInUser - * @throws RedirectException - * @throws ServerException - */ - public function language(Request $request): FormInterface - { - $user = Common::ensureLoggedIn(); - // TODO Add support missing settings - - $form = Form::create([ - FormFields::language($user->getActor(), context_actor: null, label: _m('Languages'), help: _m('The languages you understand, so you can see primarily content in those'), multiple: true, required: false, use_short_display: false), - ['save_languages', SubmitType::class, ['label' => _m('Proceed to order selected languages')]], - ]); - - $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - $data = $form->getData(); - - if (!\is_null($data['languages'])) { - $selected_langs = DB::findBy('language', ['locale' => $data['languages']]); - $existing_langs = DB::dql( - 'select l from language l join actor_language al with l.id = al.language_id where al.actor_id = :actor_id', - ['actor_id' => $user->getId()], - ); - - $new_langs = array_udiff($selected_langs, $existing_langs, fn ($l, $r) => $l->getId() <=> $r->getId()); - $removing_langs = array_udiff($existing_langs, $selected_langs, fn ($l, $r) => $l->getId() <=> $r->getId()); - foreach ($new_langs as $l) { - DB::persist(ActorLanguage::create(['actor_id' => $user->getId(), 'language_id' => $l->getId(), 'ordering' => 0])); - } - - if (!empty($removing_langs)) { - $actor_langs_to_remove = DB::findBy('actor_language', ['actor_id' => $user->getId(), 'language_id' => F\map($removing_langs, fn ($l) => $l->getId())]); - foreach ($actor_langs_to_remove as $lang) { - DB::remove($lang); - } - } - - Cache::delete(ActorLanguage::cacheKeys($user)['actor-langs']); - ActorLanguage::normalizeOrdering($user); // In case the user doesn't submit the other page - DB::flush(); - unset($data['languages']); - - throw new RedirectException('settings_sort_languages', ['_fragment' => null]); // TODO doesn't clear fragment - } - } - return $form; - } - /** * Local user personal information panel * @@ -358,54 +303,4 @@ class UserPanel extends Controller return $tabbed_forms; } - - /** - * Controller for defining the ordering of a users' languages - * - * @throws NoLoggedInUser - * @throws RedirectException - * @throws ServerException - */ - public function sortLanguages(Request $request): array - { - $user = Common::ensureLoggedIn(); - - $langs = DB::dql('select l.locale, l.long_display, al.ordering from language l join actor_language al with l.id = al.language_id where al.actor_id = :id order by al.ordering ASC', ['id' => $user->getId()]); - - $form_entries = []; - foreach ($langs as $l) { - $form_entries[] = [$l['locale'], IntegerType::class, ['label' => _m($l['long_display']), 'data' => $l['ordering']]]; - } - - $form_entries[] = ['save_language_order', SubmitType::class, []]; - $form_entries[] = ['go_back', SubmitType::class, ['label' => _m('Return to settings page')]]; - $form = Form::create($form_entries); - - $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - /** @var SubmitButton $button */ - $button = $form->get('go_back'); - $go_back = $button->isClicked(); - $data = $form->getData(); - asort($data); // Sort by the order value - $data = array_keys($data); // This keeps the order and gives us a unique number for each - foreach ($data as $order => $locale) { - $lang = Language::getByLocale($locale); - $actor_lang = DB::getReference('actor_language', ['actor_id' => $user->getId(), 'language_id' => $lang->getId()]); - $actor_lang->setOrdering($order + 1); - } - DB::flush(); - if (!$go_back) { - // Stay on same page, but force update and prevent resubmission - throw new RedirectException('settings_sort_languages'); - } else { - throw new RedirectException('settings', ['open' => 'account', '_fragment' => 'save_account_info_languages']); - } - } - - return [ - '_template' => 'settings/sort_languages.html.twig', - 'form' => $form->createView(), - ]; - } } diff --git a/src/Routes/Main.php b/src/Routes/Main.php index a1a98952c8..b455918131 100644 --- a/src/Routes/Main.php +++ b/src/Routes/Main.php @@ -70,6 +70,5 @@ abstract class Main } $r->connect('settings', '/settings', [C\UserPanel::class, 'allSettings']); - $r->connect('settings_sort_languages', '/settings/sort_languages', [C\UserPanel::class, 'sortLanguages']); } }