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

translateOrNew not saving because of deleteTranslations #410

Open
shelleychristie opened this issue May 13, 2024 · 3 comments
Open

translateOrNew not saving because of deleteTranslations #410

shelleychristie opened this issue May 13, 2024 · 3 comments
Labels

Comments

@shelleychristie
Copy link

This is the update method in my controller. The idea is that in my view I have a table, one row for each language. The user fills the table, and the translations will be updated accordingly (if they leave it empty, then no translation for that language.) For the request, I used form array syntax like so in my blade file, following the documentation.
<input type="text" name="{{$locale}}[name]" />

        $subcat = ProductSubcategory::findOrFail($id);

        $subcat->product_category_id = $request->product_category_id;
        foreach ($helper->languageCodes() as $code) {
            if ($request->{$code}['name'] == null) {
                // if null, remove translation, but not if it's the fallback_locale
                if ($code != config('translatable.fallback_locale')) {
                    $subcat->deleteTranslations($code);
                }
            } else {
                $subcat->translateOrNew($code)->name = $request->{$code}['name'];
                if ($code == config('translatable.fallback_locale')) {
                    // this is filling in another field on the main table
                    $subcat->product_subcategory_name = $request->{$code}['name'];
                }
            }
            // $subcat->save();
            // if I save here, it works. But I wouldn't want to save on loop.
        }

        $subcat->save();

When I save my subcategory model, the translations don't get updated, but the $subcat->product_subcategory_name is saved.
If I do $subcat->save() inside the foreach loop, it works, but I don't think that's the intended method.
Any help is appreciated, thank you.

Other notes:

  • $helper->languageCodes() just returns an array of the locale codes, like the package's locales helper,
  • laravel-translatable v11.9.1
  • Laravel framework v8.83.27
@Oleksandr-Moik
Copy link
Contributor

Try to use $subcat->push() after loop

https://laravel.com/docs/11.x/eloquent-relationships#the-push-method

@shelleychristie
Copy link
Author

Thanks for the reply. I've tried using push() in place of save() but it doesn't seem to be making a difference. Interestingly, if I dd($subcat) right before push(), it shows that the translations relation is not updated (new translations aren't there, no updates). Another note, when I comment out the part with deleteTranslations(), push works. Not sure why, does deleteTranslations somehow affect the ability to save?

@shelleychristie
Copy link
Author

I think I may have figured out what went wrong. In the package's translatable trait, the deleteTranslations method reloads the translations from DB whenever it is called.

Astrotomic\Translatable;

public function deleteTranslations($locales = null): void
    {
        if ($locales === null) {
            $translations = $this->translations()->get();
        } else {
            $locales = (array) $locales;
            $translations = $this->translations()->whereIn($this->getLocaleKey(), $locales)->get();
        }

        $translations->each->delete();

        // we need to manually "reload" the collection built from the relationship
        // otherwise $this->translations()->get() would NOT be the same as $this->translations
        $this->load('translations');
    }

So even though I already made changes to the translations through $subcat, because the translations are reloaded from DB the model loses all of the changes by the time it reaches save() or push().

To work around this, I have made a custom trait that extends Translatable and added a deleteTranslationsWithoutReloading method that is a copy of the deleteTranslations method but without reloading the translations. I then replaced all the models that used the Translatable trait and replaced it with my CustomTranslatable.

trait CustomTranslatable
{
    use Translatable;

    // vendor's deleteTranslations always reloads the collection from DB, preventing us from updating translations on the same model.
    public function deleteTranslationsWithoutReloading($locales = null): void
    {
        if ($locales === null) {
            $translations = $this->translations()->get();
        } else {
            $locales = (array) $locales;
            $translations = $this->translations()->whereIn($this->getLocaleKey(), $locales)->get();
        }

        $translations->each->delete();

        // we need to manually "reload" the collection built from the relationship
        // otherwise $this->translations()->get() would NOT be the same as $this->translations

        // reload commented. see Astrotomic\Translatable\Translatable;
        // $this->load('translations');
    }
}

I replaced the deleteTranslations() with deleteTranslationWithoutReloading() in the controller and can now use $subcat->save() right after the loop and it works as expected. If there are better ways to do this, I'd appreciate the input. Thanks!

@shelleychristie shelleychristie changed the title translateOrNew not saving translateOrNew not saving because of deleteTranslations May 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants