Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem using livewire #58

Open
ivanbar opened this issue May 26, 2022 · 11 comments
Open

Problem using livewire #58

ivanbar opened this issue May 26, 2022 · 11 comments

Comments

@ivanbar
Copy link

ivanbar commented May 26, 2022

Hello, Ive problems using livewire. All works fine, but when I type the input, data refresh and dissapear data from views/livewire/filtro.
When I click on url, data comes well.
Ive to refresh url to view data.
Ive tried displya blade without Front Controller, clear cache, clear routes

Http/Livewire/Filtro

`use Livewire\WithPagination;

class Filtro extends Component
{

use WithPagination;

protected $paginationTheme = 'bootstrap';

protected $queryString = ['marca'];
public $marca;

public function render()
{
    return view('livewire.filtro', [
        'productos' => Producto::where('deleted',0)
                            ->where('marca', 'like', '%'.$this->marca.'%' )->paginate(20)
    ]);
}

}`

routes/web
`<?php

use Illuminate\Support\Facades\Route;

/*
Web Routes
--------------------------------------------------------------------------

*/

// Localized
Route::localized(function () {

Route::get('/anuncios', function () {
return view('front.anuncios');

});

Route::get('/', function () {
return view('front.index');
});

Route::get('/index', [App\Http\Controllers\FrontController::class, 'index'])->name('front.index');

});

Auth::routes();

Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');

Route::fallback(\CodeZero\LocalizedRoutes\Controller\FallbackController::class)
->middleware(\CodeZero\LocalizedRoutes\Middleware\SetLocale::class);`

views/livewire/filtro

`

    <div class="listing__text__top">
        <div class="listing__text__top__left">
            <h5>Todoterrenos</h5>
            <span>{{ $productos->count() }} Resultados</span>
            <input type="text"  class="form-control" placeholder="Search" wire:model.debounce.1000ms="marca" />
            <div wire:loading>
    Processing ...
            </div>
            <div wire:offline>
You are now offline.
        </div>
        <div class="listing__text__top__right">Ordenar <i class="fa fa-sort-amount-asc"></i></div>
    </div>
@if($productos->count()) @foreach($productos as $producto)
                  @if($producto->garantizado === 'Si')
                    <div class="listing__item__text__info__right pr-3">Garantizado</div>
                  @endif

            <div class="">

            <a href="{{ route('front.detalle', $producto->titulo_slug) }}"><img src="{{ asset('img/productos/'.$producto->imagen_1)}}" height="150" alt="..." class="rounded float-left pr-2"></a>
            </div>
            <div class="listing__item__text">
                <div class="listing__item__text__inside ">
                    <h5><a href="{{ route('front.detalle', $producto->titulo_slug) }}">{{ $producto->titulo }}</a></h5>

                    <div class="listing__item__text__rating">
                       
                        <span>{{ number_format($producto->km,0,',','.') }} km</span>

                        <h6>{{ number_format($producto->precio_contado,0,',','.' ) }} &euro;</h6>
                    </div>
                    <ul>
                       
                        <li><i class="fa fa-map-marker"></i> {{ $producto->municipio }}, {{ $producto->municipio_slug }}</li>
                       
                    </ul>
                </div>   
            </div>
        </div>
@endforeach

@else

No hay productos

@endif

{{ $productos->links() }}

`

App/Http/Comtrollers/FrontController

`<?php

namespace App\Http\Controllers;

use App\Models\Front;
use Illuminate\Http\Request;

use Illuminate\Support\Facades\DB;

use App\Models\Producto;
use App\Models\Link;
use Illuminate\Support\Facades\Session;

use App;

class FrontController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/

 public function anuncios()
{
    return view('front.anuncios');
}

 public function index()
{
    return view('front.index');
}



public function detalle($titulo_slug)
{

 //   dd($titulo_slug);

  if($titulo_slug !='index' && $titulo_slug !='blog'){

    $producto = Producto::where('titulo_slug',$titulo_slug)
                            ->first();

    $num = $producto->visitas;

      $num ++;

      $producto->visitas = $num ;

      $producto->save();                        


    return view('front.detalle')->with('producto',$producto);
                            }
                            
}

public function locale($lang)
{
       App::setlocale($lang);

        session(['locale' => $lang]);
    
    return view('front.index');
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
    //
}

/**
 * Remove the specified resource from storage.
 *
 * @param  \App\Models\Front  $front
 * @return \Illuminate\Http\Response
 */
public function destroy(Front $front)
{
    // 
}

}
`

@ivanvermeyen
Copy link
Contributor

Hi,

It's really hard to tell what's going on.
I also have no experience with Livewire.

@gwleuverink
Copy link

Not sure if this is the problem, but I'm also experiencing some difficulties.

Livewire makes under the hood requests to the backend, to a dedicated /livewire/message endpoint. Because of this it seems like request()->route()->getAction('localized-routes-locale') doesn't return the locale of the route the request originated from.

@mgussekloo
Copy link

mgussekloo commented Nov 21, 2022

I have the same issue. After an update, {{ \Route::localizedUrl('nl') }} results in "http://site.test/livewire/message/slideshow" (where slideshow is the name of the Livewire component). I hope this gets fixed! Seems this is a known issue with Livewire, and a number of packages exist to deal with it, such as this one. I guess it would be nice if Localized Routes was aware of Livewire, or could be made aware of it in a way.

@ivanvermeyen
Copy link
Contributor

ivanvermeyen commented Nov 23, 2022

Hello,

It seems you can configure the middleware in the Livewire config.
By default it applies the web middleware group.

If you add the SetLocale middleware to the web group (right after the session middleware), does it then apply the expected locale? In theory it should find the locale in the session.

You can not use the option omit_url_prefix_for_locale though, since no prefix means default locale then.

Some additional findings...

The /livewire/message path is hardcoded.
https://github.com/livewire/livewire/blob/e117c78f9a4b19edb294b5b576138fd1f896925a/js/connection/index.js#L41

The part that comes before that is the app_url, which is ultimately set in the Livewire config file.
https://github.com/livewire/livewire/blob/65d311c63d2d1092ad5891fd0c1c1bdbed272cee/src/LivewireManager.php#L228
https://github.com/livewire/livewire/blob/65d311c63d2d1092ad5891fd0c1c1bdbed272cee/src/LivewireManager.php#L298

Unfortunately, you can not detect the locale in a config file.
Perhaps you can update the window.livewire_app_url JS variable on runtime, to include the locale?

@ivanvermeyen
Copy link
Contributor

Hi,

Sorry for the late followup.
I did some testing, but I don't understand what's going on with the locale in Livewire.
This doesn't seem to be documented.

I created a fresh Laravel test app with this package and Livewire included.
If you like, you can download it at https://github.com/ivanvermeyen/test-app-localized-routes-livewire.
The commits will show what I changed.

Locale Problem

For some reason, Livewire's locale is always set to the last locale in my supported_locales config.
I have no clue why.

Initial page load:

Scherm­afbeelding 2023-04-05 om 12 49 32

When I click the button to update the Component:

Scherm­afbeelding 2023-04-05 om 12 49 52

Livewire requests should go through the web middleware by default, so the SetLocale middleware should run too.

Current Route / Request Problem

As mentioned before, Livewire makes ajax calls to a /livewire/message endpoint.
Therefor, the current route and request doesn't match the "expected" original URL, which makes sense.
Code that uses the current route or request won't work properly, like the Route::localizedUrl() macro.

I was able to fix this locally, but I don't know if this is a legit way.

First I need to inject the request (this is not on GitHub yet):

Scherm­afbeelding 2023-04-05 om 12 54 03

And then I inject a recreated version of the original request when we're in a Livewire requests, using a middleware.

public function handle(Request $request, Closure $next): Response
{
    if ($this->isLivewireRequest()) {
        $sessionRequest = Request::create(session('current-url'));

        $sessionRequest->setRouteResolver(function () use ($sessionRequest) {
            return Collection::make(Route::getRoutes())->first(function ($route) use ($sessionRequest) {
                return $route->matches($sessionRequest);
            });
        });

        app()->bind(LocalizedUrlGenerator::class, function () use ($sessionRequest) {
            return new LocalizedUrlGenerator($sessionRequest);
        });
    } else {
        session()->put('current-url', $request->fullUrl());
    }

    return $next($request);
}

protected function isLivewireRequest(): bool
{
    return class_exists(\Livewire\LivewireManager::class)
        && app(\Livewire\LivewireManager::class)->isLivewireRequest();
}

Now the macro works event when the Component gets updated:

Scherm­afbeelding 2023-04-05 om 13 55 27

I would need to do this for every class that uses the current route or request.

If anyone has a better understanding of how this all works, I'd love to hear it.

@gwleuverink
Copy link

Hi @ivanvermeyen thanks for the comprehensive writeup.

I've since written a temporary workaround that just works ™️. By overriding the packages UrlGenerator, detecting a Livewire request & grabbing the correct locale from the request referrer.

This is hacky as hell though, so I'd love to see a more robust solution.

I vaguely remember Caleb (Livewire's creator) talking about supporting dynamic url's for Livewire update requests in V3, which will release soon (hopefully). It might be easier to integrate with in V3.

@ivanvermeyen
Copy link
Contributor

The problem seems to be caused by temporarily updating the App locale when generating the URLs for alternative locales.
I do this to automatically fetch translated route parameters.

// Update the current locale if needed.
if ($locale !== null && $locale !== $currentLocale) {
App::setLocale($locale);
}
$url = parent::route($resolvedName, $parameters, $absolute);
// Restore the current locale if needed.
if ($locale !== null && $locale !== $currentLocale) {
App::setLocale($currentLocale);
}

If I comment out the 2 calls to App::setLocale(), the locale is correct in Livewire and the {locale}/livewire/message/{name} endpoint is used for the ajax calls.

Will try to find out why this issue is occurring.

@ivanvermeyen
Copy link
Contributor

Finally discovered the source of all evil.

In the code of the Route::localizedUrl() macro, I try to generate a URL using URL::route().
If that fails, I catch any exception and resolve the URL manually.

try {
    return URL::route($this->route->getName(), $parameters, $absolute, $locale);
} catch (InvalidArgumentException $e) {
    return '';
}

By catching the exception, the locale that was temporarily changed in the underlying UrlGenerator code, never gets restored! So I need to update the code in the UrlGenerator:

if ($locale !== null && $locale !== $currentLocale) {
    App::setLocale($locale);
}

try {
    $url = parent::route($resolvedName, $parameters, $absolute);
} finally {
    if ($locale !== null && $locale !== $currentLocale) {
        App::setLocale($currentLocale);
    }
}

I'll fix his first and then figure out how to handle the Request issues.

@gwleuverink
Copy link

gwleuverink commented Apr 6, 2023

Not sure if this helps, but you might need to add a persistent middleware to capture the locale url param

https://laravel-livewire.com/docs/2.x/security#persistent-middleware

Though it's been a while since first encountering this. If you need an extra set of eyes I'm happy to pair on it

@ivanvermeyen
Copy link
Contributor

@gwleuverink Thanks! I also came across the persistent middleware.
Although I think the web middleware group is automatically applied (locale is consistent now), people could potentially apply the middleware a different way for this package. So it's probably a good idea to use that.

@ivanvermeyen
Copy link
Contributor

After a lot of thinking and tinkering, I've come up with a working prototype that handles the Livewire requests always being the ajax endpoint instead of the expected original URL.

I could run my current test suite on it by using the current URL for now, instead of the Livewire::originalUrl().
Mind the lines that are commented out.

I pushed a few changes beforehand, to inject the Request instance in my classes' constructor, and used that instead of the Request and Route facades.

In the SetLocale middleware (temporarily?) I can now check if it's a Livewire request, and then rebind my classes with the recreated Request. The main Laravel Request en current Route stays untouched.

You can see in the middleware that I had to jump through some hoops to make everything work.
I'm not overly excited about the complexity, but at least for now, it works.

https://github.com/codezero-be/laravel-localized-routes/pull/93/files

If @gwleuverink or anyone would like to review, I'm open for any feedback.
The middleware changes are on the support-livewire branch:

https://github.com/codezero-be/laravel-localized-routes/tree/support-livewire

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants