public function single(Request $request, Technique $tech) {
$this->authorize('view', $tech);
- $tech->load('chapters');
+ $tech->load(['chapters', 'relations']);
return $tech->toJson();
}
->using(TechniqueChapter::class);
}
+ public function relations() {
+ return $this
+ ->belongsToMany(Technique::class, 'technique_relations', 'from_id', 'to_id')
+ ->withPivot('type')
+ ->using(TechniqueRelation::class);
+ }
+
public function translations() {
return $this->hasMany(TechniqueTranslation::class);
}
--- /dev/null
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Relations\Pivot;
+
+class TechniqueRelation extends Pivot
+{
+ //
+}
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::create('technique_relations', function (Blueprint $table) {
+ $table->id();
+ $table->foreignId('from_id')->references('id')->on('techniques')->constrained();
+ $table->foreignId('to_id')->references('id')->on('techniques')->constrained();
+ $table->string('type')->default('related');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('technique_relations');
+ }
+};
import { Container } from 'react-bootstrap';
import { withTranslation } from 'react-i18next';
+import List from './List';
import Outline from './Outline';
import RawHTML from '../common/RawHTML';
-import { getTranslation } from '../../helpers/Technique';
+import {
+ getRelations,
+ getTranslation,
+ hasRelations,
+ sorted,
+} from '../../helpers/Technique';
import i18n from '../../i18n';
const Detail = ({ technique }) => <Container as="article">
<RawHTML html={getTranslation(chapter, 'description', i18n.language)} />
</section>
) : null}
+ {hasRelations(technique, 'related') ? <>
+ <h2 className="mt-5">{i18n.t('techniques.seeAlso')}</h2>
+ <List techniques={sorted(getRelations(technique, 'related'))} />
+ </> : null}
</Container>;
Detail.propTypes = {
+import i18n from '../i18n';
+
+export const getRelations = (tech, type) => {
+ const rs = (tech && tech.relations) || [];
+ return type ? rs.filter(r => r && r.pivot && r.pivot.type === type) : rs;
+};
+
+export const hasRelations = (tech, type) => getRelations(tech, type).length > 0;
+
export const getTranslation = (tech, prop, lang) => {
const direct = tech.translations.find(t => t.locale === lang);
if (direct) {
export const compareTranslation = (prop, lang) => (a, b) =>
getTranslation(a, prop, lang).localeCompare(getTranslation(b, prop, lang));
+export const sorted = (techs) => [...techs].sort(compareTranslation('title', i18n.language));
+
export default {
+ compareTranslation,
+ getRelations,
getTranslation,
+ hasRelations,
+ sorted,
};
},
techniques: {
heading: 'Techniken',
+ seeAlso: 'Siehe auch',
},
tournaments: {
admins: 'Organisation',
},
techniques: {
heading: 'Techniques',
+ seeAlso: 'See also',
},
tournaments: {
admins: 'Admins',