fixed article graphql refactoring, continued to improve graphql for materials

This commit is contained in:
Bachir Soussi Chiadmi 2020-12-22 16:36:06 +01:00
parent 1dcd627cab
commit f39079c616
9 changed files with 452 additions and 192 deletions

View File

@ -5,9 +5,22 @@ type Materiau {
uuid: String!
title: String!
author: String
memo: String
body: String
short_description: String
linked_materials: [Materiau]
linked_articles: [Article]
images: [Image]
videos: [VideoLink]
tags: [Tag]
thesaurus: [Thesaurus]
memo: String
attachments: [Filefield]
# distributor:
# manufacturer:
# famille:
# index:
# reference:
# samples:
}
type Article {
@ -24,6 +37,21 @@ type Article {
tags: [Tag]
thesaurus: [Thesaurus]
date: Date
memo: String
}
type Filefield {
file: File!
description: String
}
type File {
fid: String!
uuid: String!
filename: String!
filemime: String!
filesize: String!
url: String!
}
type Link {
@ -67,6 +95,9 @@ type Image {
url: String!
alt: String
style_minicard: ImageStyle
style_cardmedium: ImageStyle
style_cardfull: ImageStyle
style_articlecardmedium: ImageStyle
}
type ImageStyle {

View File

@ -7,7 +7,7 @@ use Drupal\graphql\GraphQL\ResolverRegistryInterface;
use Drupal\graphql\GraphQL\Response\ResponseInterface;
use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase;
use Drupal\materio_graphql\GraphQL\Response\MaterioResponse;
use Drupal\Core\Url;
/**
* @SchemaExtension(
* id = "materio_extension",
@ -24,7 +24,11 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
public function registerResolvers(ResolverRegistryInterface $registry) {
$builder = new ResolverBuilder();
// Materiau
// __ __ _ _
// | \/ |__ _| |_ ___ _ _(_)__ _ _ _
// | |\/| / _` | _/ -_) '_| / _` | || |
// |_| |_\__,_|\__\___|_| |_\__,_|\_,_|
$registry->addFieldResolver('Query', 'materiau',
$builder->produce('entity_load')
->map('type', $builder->fromValue('node'))
@ -46,7 +50,20 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
$builder->compose(
$builder->produce('entity_label')
->map('entity', $builder->fromParent())
)
));
$registry->addFieldResolver('Materiau', 'body',
$builder->produce('property_path')
->map('type', $builder->fromValue('entity:node'))
->map('value', $builder->fromParent())
->map('path', $builder->fromValue('body.value'))
);
$registry->addFieldResolver('Materiau', 'short_description',
$builder->produce('property_path')
->map('type', $builder->fromValue('entity:node'))
->map('value', $builder->fromParent())
->map('path', $builder->fromValue('field_short_description.value'))
);
$registry->addFieldResolver('Materiau', 'author',
@ -55,8 +72,7 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('entity', $builder->fromParent()),
$builder->produce('entity_label')
->map('entity', $builder->fromParent())
)
);
));
// https://github.com/drupal-graphql/graphql/blob/8.x-4.x/doc/SUMMARY.md
// https://blog.chrismitchellonline.com/posts/custom_graphql_data/
@ -66,8 +82,14 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
$builder->produce('entity_reference')
->map('entity', $builder->fromParent())
->map('field', $builder->fromValue('field_linked_materials'))
)
);
));
$registry->addFieldResolver('Materiau', 'linked_articles',
$builder->compose(
$builder->produce('entity_reference')
->map('entity', $builder->fromParent())
->map('field', $builder->fromValue('field_linked_articles'))
));
$registry->addFieldResolver('Materiau', 'memo',
$builder->produce('property_path')
@ -82,18 +104,52 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('field', $builder->fromValue('field_materiau_images'))
);
// Article
$registry->addFieldResolver('Materiau', 'attachments',
$builder->produce('property_path')
->map('type', $builder->fromValue('entity:node'))
->map('value', $builder->fromParent())
->map('path', $builder->fromValue('field_attachments'))
// $builder->produce('entity_reference')
// ->map('entity', $builder->fromParent())
// ->map('field', $builder->fromValue('field_attachments'))
);
$registry->addFieldResolver('Materiau', 'videos',
$builder->produce('property_path')
->map('type', $builder->fromValue('entity:node'))
->map('value', $builder->fromParent())
->map('path', $builder->fromValue('field_video'))
);
$registry->addFieldResolver('Materiau', 'tags',
$builder->produce('entity_reference')
->map('entity', $builder->fromParent())
->map('field', $builder->fromValue('field_tags'))
);
$registry->addFieldResolver('Materiau', 'thesaurus',
$builder->produce('entity_reference')
->map('entity', $builder->fromParent())
->map('field', $builder->fromValue('field_thesaurus'))
);
// field_distributor
// field_famille
// field_index
// field_manufacturer
// field_reference
// field_samples
// _ _ _ _
// /_\ _ _| |_(_)__| |___
// / _ \| '_| _| / _| / -_)
// /_/ \_\_| \__|_\__|_\___|
$registry->addFieldResolver('Query', 'article',
$builder->produce('entity_load')
->map('type', $builder->fromValue('node'))
->map('bundles', $builder->fromValue(['article']))
->map('id', $builder->fromArgument('id'))
);
// $registry->addFieldResolver('ArticleResponse', 'article',
// $builder->callback(function (ArticleResponse $response) {
// return $response->article();
// })
// );
$registry->addFieldResolver('Article', 'id',
$builder->produce('entity_id')
@ -109,8 +165,7 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
$builder->compose(
$builder->produce('entity_label')
->map('entity', $builder->fromParent())
)
);
));
$registry->addFieldResolver('Article', 'author',
$builder->compose(
@ -118,8 +173,7 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('entity', $builder->fromParent()),
$builder->produce('entity_label')
->map('entity', $builder->fromParent())
)
);
));
$registry->addFieldResolver('Article', 'body',
$builder->produce('property_path')
@ -128,6 +182,12 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('path', $builder->fromValue('body.value'))
);
$registry->addFieldResolver('Article', 'memo',
$builder->produce('property_path')
->map('type', $builder->fromValue('entity:node'))
->map('value', $builder->fromParent())
->map('path', $builder->fromValue('field_memo.value'))
);
// https://github.com/drupal-graphql/graphql/blob/8.x-4.x/doc/SUMMARY.md
// https://blog.chrismitchellonline.com/posts/custom_graphql_data/
$registry->addFieldResolver('Article', 'linked_materials',
@ -169,8 +229,7 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
$builder->callback(function ($items) {
return $items[0];
})
)
);
));
$registry->addFieldResolver('Article', 'source',
$builder->produce('property_path')
@ -186,7 +245,67 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('path', $builder->fromValue('field_date'))
);
// Date
// ___ _ _
// | __(_) |___
// | _|| | / -_)
// |_| |_|_\___|
$registry->addFieldResolver('Filefield', 'description',
$builder->callback(function ($parent, $args) {
return $parent['description'];
})
);
$registry->addFieldResolver('Filefield', 'file',
// $builder->produce('entity_reference')
// ->map('entity', $builder->fromParent())
// ->map('field', $builder->fromValue('field_showroom'))
$builder->callback(function ($parent, $args) {
return \Drupal\file\Entity\File::load($parent['target_id']);
})
);
$registry->addFieldResolver('File', 'url',
$builder->callback(function ($parent, $args) {
return $parent->url();
})
);
$registry->addFieldResolver('File', 'filesize',
$builder->callback(function ($parent, $args) {
return $parent->getSize();
})
);
$registry->addFieldResolver('File', 'filemime',
$builder->callback(function ($parent, $args) {
return $parent->getMimeType();
})
);
$registry->addFieldResolver('File', 'filename',
$builder->callback(function ($parent, $args) {
return $parent->getFilename();
})
);
$registry->addFieldResolver('File', 'fid',
$builder->callback(function ($parent, $args) {
return $parent->id();
})
);
$registry->addFieldResolver('File', 'uuid',
$builder->callback(function ($parent, $args) {
return $parent->uuid();
})
);
// ___ _
// | \ __ _| |_ ___
// | |) / _` | _/ -_)
// |___/\__,_|\__\___|
$registry->addFieldResolver('Date', 'start',
$builder->callback(function ($parent, $args) {
return $parent[0]['value'];
@ -198,20 +317,27 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
})
);
// Link
// _ _ _
// | | (_)_ _ | |__
// | |__| | ' \| / /
// |____|_|_||_|_\_\
$registry->addFieldResolver('Link', 'url',
$builder->callback(function ($parent, $args) {
return $parent[0]['uri'];
})
);
$registry->addFieldResolver('Link', 'title',
$builder->callback(function ($parent, $args) {
return $parent[0]['title'];
})
);
// Showroom
// ___ _
// / __| |_ _____ __ ___ _ ___ ___ _ __
// \__ \ ' \/ _ \ V V / '_/ _ \/ _ \ ' \
// |___/_||_\___/\_/\_/|_| \___/\___/_|_|_|
$registry->addFieldResolver('Query', 'showroom',
$builder->produce('entity_load')
->map('type', $builder->fromValue('taxonomy_term'))
@ -234,7 +360,12 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('entity', $builder->fromParent())
);
// Tag
// _____
// |_ _|_ _ __ _
// | |/ _` / _` |
// |_|\__,_\__, |
// |___/
$registry->addFieldResolver('Query', 'tag',
$builder->produce('entity_load')
->map('type', $builder->fromValue('taxonomy_term'))
@ -257,7 +388,11 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('entity', $builder->fromParent())
);
// Thesaurus
// _____ _
// |_ _| |_ ___ ___ __ _ _ _ _ _ _ _ ___
// | | | ' \/ -_|_-</ _` | || | '_| || (_-<
// |_| |_||_\___/__/\__,_|\_,_|_| \_,_/__/
$registry->addFieldResolver('Query', 'thesaurus',
$builder->produce('entity_load')
->map('type', $builder->fromValue('taxonomy_term'))
@ -280,7 +415,11 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('entity', $builder->fromParent())
);
// VideoLink
// __ ___ _ _ _ _
// \ \ / (_)__| |___ ___| | (_)_ _ | |__
// \ V /| / _` / -_) _ \ |__| | ' \| / /
// \_/ |_\__,_\___\___/____|_|_||_|_\_\
$registry->addFieldResolver('VideoLink', 'url',
$builder->produce('property_path')
->map('type', $builder->fromValue('field_item:video_embed_field'))
@ -288,7 +427,12 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('path', $builder->fromValue('value'))
);
// Image
// ___
// |_ _|_ __ __ _ __ _ ___
// | || ' \/ _` / _` / -_)
// |___|_|_|_\__,_\__, \___|
// |___/
$registry->addFieldResolver('Image', 'id',
$builder->produce('entity_id')
->map('entity', $builder->fromParent())
@ -312,6 +456,24 @@ class MaterioSchemaExtension extends SdlSchemaExtensionPluginBase {
->map('style', $builder->fromValue('card_medium_half'))
);
$registry->addFieldResolver('Image', 'style_cardmedium',
$builder->produce('image_derivative')
->map('entity', $builder->fromParent())
->map('style', $builder->fromValue('card_medium'))
);
$registry->addFieldResolver('Image', 'style_cardfull',
$builder->produce('image_derivative')
->map('entity', $builder->fromParent())
->map('style', $builder->fromValue('card_full'))
);
$registry->addFieldResolver('Image', 'style_articlecardmedium',
$builder->produce('image_derivative')
->map('entity', $builder->fromParent())
->map('style', $builder->fromValue('article_card_medium'))
);
// Response type resolver.
$registry->addTypeResolver('Response', [
__CLASS__,

File diff suppressed because one or more lines are too long

View File

@ -1,23 +1,37 @@
fragment ArticleFields on Article {
images {
id
url
alt
style_minicard{
width
height
url
}
}
id
uuid
title
author
date{
start
end
}
source{
url
title
}
body
showroom {
id
uuid
memo
name
}
tags {
id
uuid
name
}
thesaurus {
id
uuid
name
}
linked_materials {
id
title
memo
body
images {
id
url
@ -27,6 +41,45 @@ fragment ArticleFields on Article {
height
url
}
style_cardmedium{
width
height
url
}
style_cardfull{
width
height
url
}
}
}
images {
id
url
alt
style_minicard{
width
height
url
}
style_cardmedium{
width
height
url
}
style_cardfull{
width
height
url
}
style_articlecardmedium{
width
height
url
}
}
videos {
url
}
memo
}

View File

@ -38,7 +38,7 @@ export default {
this.$router.push({
name:`article`,
params: { alias:this.alias },
query: { uuid: this.item.uuid }
query: { nid: this.item.nid }
// meta: { uuid:this.item.uuid },
})
}

View File

@ -36,7 +36,7 @@
<img
class="lazy"
v-lazy="index"
:data-src="img.img_styles.card_medium"
:data-src="img.style_cardmedium.url"
:title="img.title"
/>
<img
@ -49,7 +49,7 @@
<CoolLightBox
:items="item.images"
:index="lightbox_index"
srcName="src"
srcName="url"
:loop="true"
@close="lightbox_index = null">
</CoolLightBox>

View File

@ -1,5 +1,5 @@
<template>
<div class="loading" v-if="!content || loading">
<div class="loading" v-if="!article || loading">
<span>Loading ...</span>
</div>
<article class="article" v-else>
@ -25,12 +25,13 @@
</nav>
<div class="cols">
<div class="col col-left">
<section v-if="content.image_accroche" class="accroche">
<section v-if="image_accroche" class="accroche">
<figure>
<img
:src="content.image_accroche.src"
:alt="content.image_accroche.alt"
:title="content.image_accroche.title"
:src="image_accroche.url"
:alt="image_accroche.alt"
:title="image_accroche.title"
@click="setLightboxIndex(0)"
/>
</figure>
</section>
@ -38,39 +39,41 @@
<div class="thesaurus">
<ul>
<li
v-for="term in content.field_thesaurus" v-bind:key="term.id"
v-for="term in article.thesaurus" v-bind:key="term.id"
>{{ term.name }}</li>
</ul>
</div>
<div class="tags">
<ul>
<li
v-for="term in content.field_tags" v-bind:key="term.id"
v-for="term in article.tags" v-bind:key="term.id"
>{{ term.name }}</li>
</ul>
</div>
</section>
<section v-if="content.field_showroom" class="showroom">
<h2>{{ content.field_showroom.name }}</h2>
<a class="mail" :href="'mail:'+content.field_showroom.field_public_email">
{{ content.field_showroom.field_public_email }}</a>
<section v-if="article.showroom" class="showroom">
<h2>{{ article.showroom.name }}</h2>
<a class="mail" :href="'mail:'+article.showroom.field_public_email">
{{ article.showroom.field_public_email }}</a>
<br/>
<a class="phone" :href="'tel:' + content.field_showroom.field_public_phone">
{{ content.field_showroom.field_public_phone }}</a>
<a class="phone" :href="'tel:' + article.showroom.field_public_phone">
{{ article.showroom.field_public_phone }}</a>
</section>
</div> <!-- //col-left -->
<div class="col col-right">
<section class="body" v-html="content.body"></section>
<section class="body" v-html="article.body"></section>
<CoolLightBox
:items="content.lightbox_items"
:items="lightbox_items"
:index="lightbox_index"
:loop="true"
srcName="url"
@close="lightbox_index = null">
</CoolLightBox>
<div class="gallery-wrapper">
<div
class="image"
v-for="(image, imageIndex) in content.lightbox_items"
v-for="(image, imageIndex) in lightbox_items"
v-if="imageIndex > 0"
:key="imageIndex"
@click="setLightboxIndex(imageIndex)"
:style="{ backgroundImage: 'url(' + image.thumb + ')' }"
@ -80,7 +83,7 @@
<h3 class="field__label">{{$t("materio.Linked Materials")}}</h3>
<div class="card-list">
<ul class="">
<li v-for="node in content.field_linked_materials" v-bind:key="node.id">
<li v-for="node in article.linked_materials" v-bind:key="node.id">
<Card :item="node" />
</li>
</ul>
@ -120,8 +123,8 @@ import { REST } from 'vuejs/api/rest-axios'
import { MGQ } from 'vuejs/api/graphql-axios'
import { print } from 'graphql/language/printer'
import gql from 'graphql-tag'
import materiauFields from 'vuejs/api/gql/materiau.fragment.gql'
// import articleFields from 'vuejs/api/gql/article.fragment.gql'
// import materiauFields from 'vuejs/api/gql/materiau.fragment.gql'
import articleFields from 'vuejs/api/gql/article.fragment.gql'
import qs from 'querystring-es3'
import Card from 'vuejs/components/Content/Card'
@ -138,7 +141,9 @@ export default {
index:-1,
prevnext:{},
uuid:null,
content:null,
article:null,
image_accroche: null,
lightbox_items: null,
loading:true,
lightbox_index:null,
}
@ -160,17 +165,17 @@ export default {
getArticle(){
console.log(this.$route);
// get the article uuid
if(this.$route.query.uuid){
if(this.$route.query.nid){
// we come from internal link with vuejs
// directly record uuid
this.uuid = this.$route.query.uuid
this.nid = this.$route.query.nid
}else if(drupalDecoupled.entity_type == 'node' && drupalDecoupled.entity_bundle == 'article'){
// we landed in an internal page
// get the uuid from drupalDeclouped, provided by materio_decoupled.module
this.uuid = drupalDecoupled.entity_uuid
this.nid = drupalDecoupled.entity_id
}
if(this.uuid){
if(this.nid){
this.loadArticle()
// get the prev next items
if(!this.items.length){
@ -191,7 +196,7 @@ export default {
},
getIndex(){
console.log("Article getIndex");
this.getItemIndex(this.uuid).then((index) => {
this.getItemIndex(this.nid).then((index) => {
this.index = index
// console.log('article index', index, this);
this.getPrevNextItems(index).then((pn) => {
@ -200,42 +205,91 @@ export default {
})
},
loadArticle(){
console.log('loadArticle', this.uuid)
console.log('loadArticle', this.nid)
this.loading = true;
let params = {
include:'field_linked_materials.images,field_showroom,field_tags,field_thesaurus,field_visuel,uid'
}
let q = qs.stringify(params)
JSONAPI.get(`node/article/${this.uuid}?${q}`)
.then(({ data }) => {
console.log('loadArticle data', data)
this.parseDataJSONAPI(data)
})
.catch(( error ) => {
console.warn('Issue with loadArticle', error)
Promise.reject(error)
})
// let ast = gql`{
// article(id: ${this.uuid}) {
// ...ArticleFields
// let params = {
// include:'field_linked_materials.images,field_showroom,field_tags,field_thesaurus,field_visuel,uid'
// }
// }
// ${ articleFields }
// `
// MGQ.post('', { query: print(ast)
// let q = qs.stringify(params)
// JSONAPI.get(`node/article/${this.uuid}?${q}`)
// .then(({ data }) => {
// console.log('loadArticle data', data)
// this.parseDataJSONAPI(data)
// })
// .then((data) => {
// console.log('loadArticle', data )
// this.parseDataGQL(data.data.article)
// })
// .catch(error => {
// .catch(( error ) => {
// console.warn('Issue with loadArticle', error)
// Promise.reject(error)
// })
let ast = gql`{
article(id: ${this.nid}) {
...ArticleFields
}
}
${ articleFields }
`
MGQ.post('', { query: print(ast)
})
.then(({ data:{data:{article}}}) => {
console.log('loadArticle', article )
this.parseDataGQL(article)
})
.catch(error => {
console.warn('Issue with loadArticle', error)
Promise.reject(error)
})
},
parseDataGQL(article){
console.log('parseDataGQL article', article)
this.article = article
this.image_accroche = article.images[0]
this.lightbox_items = [];
// fill the lightbox
for (var i = 0; i < article.images.length; i++) {
article.images[i].thumb = article.images[i].style_articlecardmedium.url
this.lightbox_items.push(article.images[i]);
}
// parse embeded videos pushing it in lightbox
for (var i = 0; i < article.videos.length; i++) {
let videoUrl = article.videos[i].url
let provider_regex = /https:\/\/(www\.)?(?<provider>youtube|vimeo)\.com\/.+/;
let match = provider_regex.exec(videoUrl)
// console.log('provider', match.groups.provider);
let video_id = null;
let video_thumb = null;
switch (match.groups.provider) {
case 'vimeo':
let vimeo_regex = /https:\/\/vimeo\.com\/(?<id>\d+)/;
video_id = vimeo_regex.exec(videoUrl).groups.id || null;
// TODO: get the vimeo thumb https://coderwall.com/p/fdrdmg/get-a-thumbnail-from-a-vimeo-video
video_thumb = "http://blogpeda.ac-poitiers.fr/ent-lyc/files/2015/06/Vimeo_icon_block.png"
break;
case 'youtube':
let youtube_regex = /https:\/\/(www\.)?youtube\.com\/watch\?v=(?<id>.+)/;
video_id = youtube_regex.exec(videoUrl).groups.id || null;
video_thumb = "http://img.youtube.com/vi/"+video_id+"/0.jpg"
break;
}
// console.log('video_id', video_id);
this.lightbox_items.push({
url: videoUrl,
title: "",
description: "",
thumb: video_thumb
});
}
console.log('this.content.lightbox_items', this.lightbox_items);
// update main page title
this.$store.commit('Common/setPagetitle', article.title)
this.loading = false;
},
// parseDataGQL(data){
// console.log('parseDataGQL data', data)
// },
parseDataJSONAPI(data){
let attrs = data.data.attributes
let relations = data.data.relationships
@ -376,48 +430,8 @@ export default {
this.loading = false;
console.log('article.content',this.content);
this.getFieldDefinition()
},
getFieldDefinition(field){
// // JSONAPI.get(`field_config/${field}`)
// // .then(({ data }) => {
// // console.log('getFieldDefinition data', data)
// // })
// // .catch(( error ) => {
// // console.warn('Issue with getFieldDefinition', error)
// // Promise.reject(error)
// // })
// REST.get('/entity/node_type/materiau?_format=json')
// .then((data) => {
// console.log('getFieldDefiintion', data)
// })
// .catch(error => {
// console.warn('Issue with getFieldDefiintion', error)
// Promise.reject(error)
// })
//
// https://stackoverflow.com/a/52612632
// https://stackoverflow.com/a/57873339
let ast = gql`{
materiau(id: 5150) {
...MateriauFields
}
}
${ materiauFields }
`
MGQ.post('', { query: print(ast)
})
.then((data) => {
console.log('getFieldDefinition', data )
})
.catch(error => {
console.warn('Issue with getFieldDefiintion', error)
Promise.reject(error)
})
},
onNext(){
// console.log('clicked on next', this.prevnext.next);
let alias = this.prevnext.next.view_node.replace(/^.?\/blabla\//g, '')

View File

@ -5,7 +5,7 @@
</div>
<div class="cards-list" v-else>
<ul>
<li v-for="item in items" v-bind:key="item.uuid">
<li v-for="item in items" v-bind:key="item.nid">
<ArticleCard :item="item"/>
</li>
</ul>

View File

@ -67,9 +67,9 @@ export default {
commit('setInfiniteState', $infiniteLoadingstate)
dispatch('getItems')
},
getItemIndex ({ dispatch, commit, state }, uuid) {
getItemIndex ({ dispatch, commit, state }, nid) {
return state.items.findIndex((e) => {
return e.uuid == uuid
return e.nid == nid
})
},
getPrevNextItems ({ dispatch, commit, state }, index) {