Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/7.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanmcclean committed Sep 19, 2024
2 parents 968d3b0 + faadc16 commit f448e9e
Show file tree
Hide file tree
Showing 19 changed files with 591 additions and 461 deletions.
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
# Changelog

## v7.9.4 (2024-09-19)

### What's fixed
* Fix issue in the REST API when using plurals as resource handles #605 by @duncanmcclean



## v7.9.3 (2024-09-17)

### What's fixed
* Fixed an error with the Has Many fieldtype when used on entries #600 #601 by @duncanmcclean



## v7.9.2 (2024-09-16)

### What's fixed
* Fixed an error that occurred when creating a model with a Has Many relationship #598 #599 by @BobWez98



## v7.9.1 (2024-09-12)

### What's fixed
* Add missing `page` variable for Blade templates #584 #590 by @duncanmcclean



## v7.9.0 (2024-09-05)

### What's new
* Improvements around unlinking relationships #582 #595 by @duncanmcclean
* When adding a new model, Runway will automatically create a blueprint for you, based on the database columns #593 by @duncanmcclean

### What's fixed
* Fixed sorting in listing tables #587 #591 by @duncanmcclean
* Fixed an issue where relationship fields weren't showing in the fieldtype selector #588 #592 by @duncanmcclean

### What's removed
* Removed the `runway:generate-blueprints` command #594 by @duncanmcclean



## v7.8.0 (2024-08-14)

### What's new
Expand Down
6 changes: 2 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
"authors": [
{
"name": "Duncan McClean",
"email": "duncan@doublethree.digital",
"homepage": "https://duncanmcclean.com",
"role": "Developer"
"email": "duncan@statamic.com"
}
],
"autoload": {
Expand Down Expand Up @@ -48,7 +46,7 @@
"pixelfear/composer-dist-plugin": "^0.1.5",
"spatie/ignition": "^1.15",
"spatie/invade": "^2.1",
"statamic/cms": "^5.7.0"
"statamic/cms": "^5.25.0"
},
"require-dev": {
"laravel/pint": "^1.0",
Expand Down
20 changes: 0 additions & 20 deletions docs/blueprints.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,26 +134,6 @@ You may also run this same command for all resources pending a migration.
php please runway:generate-migrations
```

## Generating blueprints from your database

If you've already got an Eloquent model setup, Runway can help you turn it into a blueprint!

Before you can generate blueprints, you'll need to have migrated your database already.

As well as having your model setup, you will also need to add the resource(s) to your `config/runway.php` config.

To generate a blueprint for a specific resource:

```
php please runway:generate-blueprints resource-handle
```

You may also run this same command for all resources:

```
php please runway:generate-blueprints
```

## Computed Fields

Like Statamic Core, Runway supports the concept of Computed Fields. However, instead of the computed values being part of a callback in your `AppServiceProvider`, they're accessors on your Eloquent model.
Expand Down
117 changes: 95 additions & 22 deletions docs/fieldtypes.md → docs/relationships.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
---
title: Fieldtypes
title: Relationships
---

Runway provides two fieldtypes to let you manage Eloquent Relationships within Statamic:

* Belongs To
* Useful for `belongsTo` relationships.
* Has Many
* Useful for `hasMany` & `belongsToMany` relationships.

You can also use these fieldtypes in Entry & Term blueprints, to relate entries/terms to Eloquent models.
Relationships are an important part of any web application. Most of your models will be related in some way to other models. Runway provides a way to manage those relationships within Statamic.

## Belongs To

The **Belongs To** fieldtype allows you to relate to a single Eloquent model.
Runway provides a dedicated fieldtype to manage [`belongsTo`](https://laravel.com/docs/master/eloquent-relationships#one-to-many-inverse) relationships within Statamic.

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Post extends Model
{
public function author(): BelongsTo
{
return $this->belongsTo(Author::class);
}
}
```

```yaml
-
handle: author_id
field:
type: belongs_to
display: Author
resource: author
```
When used on a Runway blueprint, you should ensure that the field handle matches the column name in the database.
You should make sure that the field handle matches the column name in the database.
### Templating
Expand All @@ -38,19 +57,35 @@ Written by {{ author:first_name }} {{ author:last_name }} ({{ author:location }}

## Has Many

![Screenshot of the Has Many Fieldtype](/img/runway/has-many-fieldtype.png)

The **Has Many** fieldtype allows you to relate to multiple Eloquent models.

When used on a Runway blueprint, you should ensure the field handle matches the name of the Eloquent relationship in your model.
Runway provides a dedicated fieldtype to manage [`hasMany`](https://laravel.com/docs/master/eloquent-relationships#one-to-many) relationships within Statamic.

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Author extends Model
{
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
```

:::note Note!
Statamic doesn't support camel case field handles, which means that in some cases it may not be possible to match the field handle with the name of the Eloquent relationship.
```yaml
-
handle: posts
field:
type: has_many
display: Posts
resource: post
```
In such case, you can either:
* Use snake case for the field handle and Runway will be smart enough to figure out which relationship you're trying to use (for example: the `featured_posts` field handle will be used to relate to the `featuredPosts` relationship).
* Use the `relationship_name` option to specify the name of the Eloquent relationship.
:::
You should ensure that the field handle matches the name of the Eloquent relationship in your model (the method name).
### Templating
Expand All @@ -76,3 +111,41 @@ Loop through the models and do anything you want with the data.
| `title_format` | Configure the title format used for displaying results in the fieldtype. You can use Antlers to pull in model data. |
| `reorderable` | Determines whether the models can be reordered. Defaults to `false`. |
| `order_column` | When reordering is enabled, this determines which column should be used for storing the sort order. When the relationship uses a pivot table, the order column must exist on the pivot table. |

## Belongs To Many

The Has Many fieldtype is also compatible with [`belongsToMany`](https://laravel.com/docs/master/eloquent-relationships#many-to-many) relationships. You can use the Has Many fieldtype on both sides of the relationship.

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Category extends Model
{
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
}
```

```yaml
-
handle: posts
field:
type: has_many
display: Posts
resource: post
```
You should ensure that the field handle matches the name of the Eloquent relationship in your model (the method name).
For more information on templating with the Has Many fieldtype and the config options available, see the [Has Many](#content-has-many) section.
## Polymorphic Relationships
Runway doesn't currently support Polymorphic relationships out of the box, since they can get pretty complicated. If you need it, please [upvote this feature request](https://github.com/statamic-rad-pack/runway/discussions/245).
136 changes: 136 additions & 0 deletions resources/js/components/inputs/relationship/Item.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<template>

<div
class="item select-none"
:class="{ 'invalid': item.invalid }"
>
<div class="item-move" v-if="sortable">&nbsp;</div>
<div class="item-inner">
<div v-if="statusIcon" class="little-dot rtl:ml-2 ltr:mr-2 hidden @sm:block" :class="item.status" />

<div
v-if="item.invalid"
v-tooltip.top="__('An item with this ID could not be found')"
v-text="__(item.title)" />

<a v-if="!item.invalid && editable" @click.prevent="edit" v-text="__(item.title)" class="truncate" v-tooltip="item.title" :href="item.edit_url" />

<div v-if="!item.invalid && !editable" v-text="__(item.title)" />

<inline-edit-form
v-if="isEditing"
:item="item"
:component="formComponent"
:component-props="formComponentProps"
@updated="itemUpdated"
@closed="isEditing = false"
/>

<div class="flex items-center flex-1 justify-end">
<div v-if="item.hint" v-text="item.hint" class="text-4xs text-gray-600 uppercase whitespace-nowrap rtl:ml-2 ltr:mr-2 hidden @sm:block" />

<div class="flex items-center" v-if="!readOnly">
<dropdown-list>
<dropdown-item :text="__('Edit')" @click="edit" v-if="editable" />
<dropdown-item :text="__('Unlink')" class="warning" @click="remove" />
</dropdown-list>
</div>
</div>

</div>

<confirmation-modal
v-if="showDeletionConfirmationModel"
:title="__('Unlink')"
:danger="true"
:buttonText="__('Delete')"
@confirm="showDeletionConfirmationModel = false; $emit('removed')"
@cancel="showDeletionConfirmationModel = false"
>
<div>{{ __('Unlinking this model will result in it being deleted. Are you sure you want to do this?') }}</div>
</confirmation-modal>

</div>

</template>

<script>
/**
* This component is a copy of Statamic's RelatedItem component, but it adds a
* confirmation modal when deleting models.
*/
import InlineEditForm from '../../../../../vendor/statamic/cms/resources/js/components/inputs/relationship/InlineEditForm.vue';
export default {
components: {
InlineEditForm
},
inject: {
storeName: {
default: null
}
},
props: {
item: Object,
config: Object,
statusIcon: Boolean,
editable: Boolean,
sortable: Boolean,
readOnly: Boolean,
formComponent: String,
formComponentProps: Object,
},
data() {
return {
isEditing: false,
showDeletionConfirmationModel: false,
}
},
computed: {
unlinkBehavior() {
return this.$parent.$parent.meta.unlinkBehavior;
}
},
methods: {
edit() {
if (! this.editable) return;
if (this.item.invalid) return;
if (this.item.reference && Object.entries(this.$store.state.publish).find(([key, value]) => value.reference === this.item.reference)) {
this.$toast.error(__("You're already editing this item."));
return;
}
this.isEditing = true;
},
itemUpdated(responseData) {
this.item.title = responseData.title;
this.item.published = responseData.published;
this.item.private = responseData.private;
this.item.status = responseData.status;
this.$events.$emit(`live-preview.${this.storeName}.refresh`);
},
remove() {
if (this.unlinkBehavior === 'delete') {
this.showDeletionConfirmationModel = true;
return;
}
this.$emit('removed');
},
}
}
</script>
10 changes: 6 additions & 4 deletions resources/js/cp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import PublishForm from './components/resources/PublishForm.vue'
import ResourceView from './components/resources/View.vue'
import PublishForm from './components/resources/PublishForm.vue';
import ResourceView from './components/resources/View.vue';
import RelatedItem from './components/inputs/relationship/Item.vue';

Statamic.$components.register('runway-publish-form', PublishForm)
Statamic.$components.register('resource-view', ResourceView)
Statamic.$components.register('runway-publish-form', PublishForm);
Statamic.$components.register('resource-view', ResourceView);
Statamic.$components.register('runway-related-item', RelatedItem);
Loading

0 comments on commit f448e9e

Please sign in to comment.