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

Add methods getTranslationChanges() and wasTranslationChanged() #231

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,25 @@ echo $post->translate('fr')->title; // Mon premier post

## Tutorials

* [How To Add Multilingual Support to Eloquent](https://laravel-news.com/how-to-add-multilingual-support-to-eloquent)
* [How To Build An Efficient and SEO Friendly Multilingual Architecture For Your Laravel Application](https://mydnic.be/post/how-to-build-an-efficient-and-seo-friendly-multilingual-architecture-for-your-laravel-application)
* [How to Add Multi-Language Models to Laravel QuickAdminPanel](https://quickadminpanel.com/blog/how-to-add-multi-language-models-to-laravel-quickadminpanel/)
- [How To Add Multilingual Support to Eloquent](https://laravel-news.com/how-to-add-multilingual-support-to-eloquent)
- [How To Build An Efficient and SEO Friendly Multilingual Architecture For Your Laravel Application](https://mydnic.be/post/how-to-build-an-efficient-and-seo-friendly-multilingual-architecture-for-your-laravel-application)
- [How to Add Multi-Language Models to Laravel QuickAdminPanel](https://quickadminpanel.com/blog/how-to-add-multi-language-models-to-laravel-quickadminpanel/)

## Credits

* [Tom Witkowski](https://github.com/Gummibeer) _current maintainer_
* [Dimitrios Savvopoulos](https://github.com/dimsav) _original author_
* [David Llop](https://github.com/Lloople) _refactoring testsuite_
* [Caneco](https://github.com/caneco) _artwork_
* [All Contributors](https://github.com/Astrotomic/laravel-translatable/graphs/contributors)
- [Tom Witkowski](https://github.com/Gummibeer) _current maintainer_
- [Dimitrios Savvopoulos](https://github.com/dimsav) _original author_
- [David Llop](https://github.com/Lloople) _refactoring testsuite_
- [Caneco](https://github.com/caneco) _artwork_
- [All Contributors](https://github.com/Astrotomic/laravel-translatable/graphs/contributors)

## Versions

| Package | Laravel | PHP |
| :--- | :--- | :--- |
| **v11.6 - v11.9** | `5.8.* / 6.* / 7.* / 8.*` | `>=7.2` |
| Package | Laravel | PHP |
| :---------------- | :---------------------------- | :-------- |
| **v11.6 - v11.9** | `5.8.* / 6.* / 7.* / 8.*` | `>=7.2` |
| **v11.4 - v11.5** | `5.6.* / 5.7.* / 5.8.* / 6.*` | `>=7.1.3` |
| **v11.0 - v11.3** | `5.6.* / 5.7.* / 5.8.*` | `>=7.1.3` |
| **v11.0 - v11.3** | `5.6.* / 5.7.* / 5.8.*` | `>=7.1.3` |

## Treeware

Expand All @@ -88,4 +88,3 @@ It’s now common knowledge that one of the best tools to tackle the climate cri
You can buy trees at [https://offset.earth/treeware](https://plant.treeware.earth/Astrotomic/laravel-translatable)

Read more about Treeware at [https://treeware.earth](https://treeware.earth)

29 changes: 14 additions & 15 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
# Table of contents

* [Introduction](README.md)
* [Issues](issues.md)
* [Changelog](changelog.md)
* [FAQ](faq.md)
* [Installation](installation.md)
- [Introduction](README.md)
- [Issues](issues.md)
- [Changelog](changelog.md)
- [FAQ](faq.md)
- [Installation](installation.md)

## Package

* [Interface](package/interface.md)
* [Methods](package/methods.md)
* [Scopes](package/scopes.md)
* [Fallback locale](package/fallback-locale.md)
* [Locales helper](package/locales-helper.md)
* [Validation Rule Factory](package/validation-rule-factory.md)
- [Interface](package/interface.md)
- [Methods](package/methods.md)
- [Scopes](package/scopes.md)
- [Fallback locale](package/fallback-locale.md)
- [Locales helper](package/locales-helper.md)
- [Validation Rule Factory](package/validation-rule-factory.md)

## Usage

* [Attributes](usage/attributes.md)
* [Forms](usage/forms.md)
* [Pivot Model](usage/pivot-model.md)

- [Attributes](usage/attributes.md)
- [Forms](usage/forms.md)
- [Pivot Model](usage/pivot-model.md)
241 changes: 120 additions & 121 deletions docs/changelog.md

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ Please see the installation steps to understand how your database should be stru
If your properties are written in english, we recommend using these commands in your migrations:

```php
// We insert the old attributes into the fresh translation table:
// We insert the old attributes into the fresh translation table:
\DB::statement("insert into country_translations (country_id, name, locale) select id, name, 'en' from countries");

// We drop the translation attributes in our main table:
// We drop the translation attributes in our main table:
Schema::table('posts', function ($table) {
$table->dropColumn('title');
$table->dropColumn('content');
Expand Down Expand Up @@ -58,8 +58,8 @@ If you see the following mysql error:
```text
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create table 'my_database.#sql-455_63'
(errno: 150) (SQL: alter table `country_translations`
add constraint country_translations_country_id_foreign foreign key (`country_id`)
(errno: 150) (SQL: alter table `country_translations`
add constraint country_translations_country_id_foreign foreign key (`country_id`)
references `countries` (`id`) on delete cascade)
```

Expand Down Expand Up @@ -92,4 +92,3 @@ Schema::create('language_translations', function(Blueprint $table){
```

The best solution though would be to update your mysql version. And **always make sure you have the same version both in development and production environment!**

27 changes: 20 additions & 7 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ composer require astrotomic/laravel-translatable
We copy the configuration file to our project.

```bash
php artisan vendor:publish --tag=translatable
php artisan vendor:publish --tag=translatable
```

After this you will have to configure the `locales` your app should use.
Expand All @@ -40,16 +40,19 @@ That's the only configuration key you **have** to adjust. All the others have a
In this example, we want to translate the model `Post`. We will need an extra table `post_translations`:

{% code title="create\_posts\_table.php" %}

```php
Schema::create('posts', function(Blueprint $table) {
$table->increments('id');
$table->string('author');
$table->timestamps();
});
```

{% endcode %}

{% code title="create\_post\_translations\_table" %}

```php
Schema::create('post_translations', function(Blueprint $table) {
$table->increments('id');
Expand All @@ -62,74 +65,84 @@ Schema::create('post_translations', function(Blueprint $table) {
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
});
```

{% endcode %}

## Models

The translatable model `Post` should [use the trait](http://www.sitepoint.com/using-traits-in-php-5-4/) `Astrotomic\Translatable\Translatable`. The default convention for the translation model is `PostTranslation`. The array `$translatedAttributes` contains the names of the fields being translated in the `PostTranslation` model.

{% code title="Post.php" %}

```php
use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Astrotomic\Translatable\Translatable;

class Post extends Model implements TranslatableContract
{
use Translatable;

public $translatedAttributes = ['title', 'content'];
protected $fillable = ['author'];
}
```

{% endcode %}

{% code title="PostTranslation.php" %}

```php
class PostTranslation extends Model
{
public $timestamps = false;
protected $fillable = ['title', 'content'];
}
```

{% endcode %}

### Custom foreign key

You may also define a custom foreign key for the package to use, e.g. in case of single table inheritance. So, you have a child class `ChildPost` that inherits from `Post` class, but has the same database table as its parent.

{% code title="ChildPost.php" %}

```php
class ChildPost extends Post
class ChildPost extends Post
{
protected $table = 'posts';
}
```

{% endcode %}

You will have to create a Translation Class for it.

{% code title="ChildPostTranslation.php" %}

```php
use Illuminate\Database\Eloquent\Model;

class ChildPostTranslation extends Model
class ChildPostTranslation extends Model
{
protected $table = 'post_translations';
public $timestamps = false;
protected $fillable = ['title', 'content'];
protected $fillable = ['title', 'content'];
}
```

{% endcode %}

This will try to get data from `post_translations` table using foreign key `child_post_id` according to Laravel. So, in this case, you will have to change the property `$translationForeignKey` to your `'post_id'`.

{% code title="ChildPost.php" %}

```php
class ChildPost extends Post
class ChildPost extends Post
{
protected $table = 'posts';
protected $translationForeignKey = 'post_id';
}
```
{% endcode %}

{% endcode %}
1 change: 0 additions & 1 deletion docs/issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
Find yourself stuck using the package? Found a bug? Do you have general questions or suggestions for improving the package? Feel free to [create an issue on GitHub](https://github.com/Astrotomic/laravel-translatable/issues), we’ll try to address it as soon as possible.

If you’ve found a bug regarding security please mail [dev.gummibeer@gmail.com](mailto:dev.gummibeer@gmail.com) instead of using the issue tracker.

32 changes: 32 additions & 0 deletions src/Translatable/Translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Astrotomic\Translatable\Traits\Relationship;
use Astrotomic\Translatable\Traits\Scopes;
use Astrotomic\Translatable\Validation\RuleFactory;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
Expand Down Expand Up @@ -458,4 +459,35 @@ public function __isset($key)
{
return $this->isTranslationAttribute($key) || parent::__isset($key);
}

public function getTranslationChanges(): array
{
switch (config('translatable.rule_factory.format')) {
case RuleFactory::FORMAT_KEY:
$replacementFunc = function (string $key, string $locale): string {
return $key . ':' . $locale;
};
break;
default:
$replacementFunc = function (string $key, string $locale): string {
return $locale . '.' . $key;
};
}
Tschoatscho marked this conversation as resolved.
Show resolved Hide resolved
$translationChanges = array();
foreach ($this->translations as $translation) {
$locale = $translation->locale;
foreach ($translation->getChanges() as $attribute => $value) {
$translationChanges[$replacementFunc($attribute, $locale)] = $value;
Tschoatscho marked this conversation as resolved.
Show resolved Hide resolved
Tschoatscho marked this conversation as resolved.
Show resolved Hide resolved
}
}
return $translationChanges;
}

public function wasTranslationChanged($attributes = null): bool
{
return $this->hasChanges(
$this->getTranslationChanges(),
is_array($attributes) ? $attributes : func_get_args()
);
Tschoatscho marked this conversation as resolved.
Show resolved Hide resolved
}
}
50 changes: 48 additions & 2 deletions tests/TranslatableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Astrotomic\Translatable\Tests\Eloquent\Person;
use Astrotomic\Translatable\Tests\Eloquent\Vegetable;
use Astrotomic\Translatable\Tests\Eloquent\VegetableTranslation;
use Astrotomic\Translatable\Validation\RuleFactory;
use Illuminate\Database\Eloquent\MassAssignmentException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\App;
Expand Down Expand Up @@ -438,10 +439,10 @@ public function it_returns_if_attribute_is_translated(): void
/** @test */
public function config_overrides_apps_locale(): void
{
$veegtable = factory(Vegetable::class)->create(['name:de' => 'Erbsen']);
$vegetable = factory(Vegetable::class)->create(['name:de' => 'Erbsen']);
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved
App::make('config')->set('translatable.locale', 'de');

static::assertEquals('Erbsen', $veegtable->name);
static::assertEquals('Erbsen', $vegetable->name);
}

/** @test */
Expand Down Expand Up @@ -1058,4 +1059,49 @@ public function it_can_restore_translations_in_a_transaction()
$this->assertDatabaseHas('vegetables', ['identity' => $vegetable->identity]);
$this->assertDatabaseHas('vegetable_translations', ['vegetable_identity' => $vegetable->identity]);
}

/** @test */
public function it_returns_no_translation_changes_for_unchanged_model()
Tschoatscho marked this conversation as resolved.
Show resolved Hide resolved
{
$vegetable = factory(Vegetable::class)->create([
'en' => ['name' => 'Peas'],
'de' => ['name' => 'Erbsen']
]);
$changes = $vegetable->getTranslationChanges();
static::assertIsArray($changes);
static::assertEmpty($changes);
static::assertFalse($vegetable->wasTranslationChanged());
}

/** @test */
public function it_returns_translation_changes_for_changed_model()
Tschoatscho marked this conversation as resolved.
Show resolved Hide resolved
{
$vegetable = factory(Vegetable::class)->create([
'en' => ['name' => 'Peas'],
'de' => ['name' => 'Birnen']
]);
$vegetable->fill(['de' => ['name' => 'Erbsen']]);
$vegetable->save();

static::assertEquals(['de.name' => 'Erbsen'], $vegetable->getTranslationChanges());
static::assertTrue($vegetable->wasTranslationChanged());
static::assertTrue($vegetable->wasTranslationChanged('de.name'));
static::assertFalse($vegetable->wasTranslationChanged('en.name'));
}

/** @test */
public function it_returns_translation_changes_in_format_array()
{
$this->app->make('config')->set('translatable.rule_factory.format', RuleFactory::FORMAT_KEY);
$vegetable = factory(Vegetable::class)->create([
'en' => ['name' => 'Peas'],
'de' => ['name' => 'Birnen']
]);
$vegetable->fill(['de' => ['name' => 'Erbsen']]);
$vegetable->save();

static::assertEquals(['name:de' => 'Erbsen'], $vegetable->getTranslationChanges());
static::assertTrue($vegetable->wasTranslationChanged('name:de'));
static::assertFalse($vegetable->wasTranslationChanged('de.name'));
}
}