booksql-laravel

https://cloud.tencent.com/developer/article/1413095
简单template

laravel cors有个package防止CORS错误❌
config->lighthouse.php(要先在下面第10步骤)
\Fruitcake\Cors\HandleCors::class

准备

安装国内镜像https://cloud.tencent.com/developer/article/1464303,否则install要等到天荒地老。。弄了三个小时都没开始,弄到自己哭!!怀疑我是不是学code的料!@!!!
composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/
我修改打开了配置文件(private/etc/php.ini.default)里面的三样https://blog.csdn.net/weixin_40952369/article/details/80673975

开干

1.composer create-project --prefer-dist laravel/laravel booksql-laravel(不要跟到用这种 laravel new booksql-laravel
2.DB_DATABASE配置
3.php artisan make:model Category -a
4.php artisan make:model Book -a
5.改写关系Category.php & Book.php

    protected $guarded = [];

    public function books()
    {
        return $this->hasMany(Book::class);
    }
--------------------------------------------------
    protected $guarded = []; //为了使用seed

    public function category() 
    {
        return $this->belongsTo(Category::class);
    }

6.migrations改 up 然后php artisan migrate

            $table->increments('id');
            $table->string('title');
            $table->string('author');
            $table->string('image')->nullable();
            $table->text('description')->nullable();
            $table->string('link')->nullable();
            $table->boolean('featured')->default(false);
            $table->unsignedInteger('category_id');//因为有hasMany关系设置这个
            $table->foreign('category_id')->references('id')->on('categories')->onUpdate('cascade');
            $table->timestamps();
--------------------------------------------------------------
        Schema::create('categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->timestamps();
        });
  1. php artisan make:seed CategoriesTableSeeder
    php artisan make:seed BooksTableSeeder
    更改两个seeder里面的内容并且
    seeds->DatabaseSeeder.php 修改:
    public function run()
    {
        // $this->call(UsersTableSeeder::class);
        $this->call(CategoriesTableSeeder::class);
        $this->call(BooksTableSeeder::class);
    }

然后php artisan migrate:fresh --seed

  1. public下面添加所有图片资源img
  2. 添加lighthouse库 composer require nuwave/lighthouse

⚠️lighthouse就是一个server,不用连xampp,只用连数据库

  1. 将默认模式发布到 graphql/schema.graphql.(publish the default schema)
    php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schema
╭─[email protected]. /Applications/booksql-laravel  
╰─➤  php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schema 
Copied File [/vendor/nuwave/lighthouse/assets/default-schema.graphql] To [/graphql/schema.graphql]
Publishing complete.

php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=config

╭─[email protected]./booksql-laravel  
╰─➤  php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=config 
Copied File [/vendor/nuwave/lighthouse/src/lighthouse.php] To [/config/lighthouse.php]
Publishing complete.

安装playground(它就好像 GraphQL 专用的 Postman,但有几个版本,# prisma-labs/graphql-playground
有些是app我下了又删了,还安了个Chrome的graphql插件点开就找不到server。期间卡了一爆,不知怎样打开这个tool。。各种错误❌心累死了
php artisan lighthouse:clear-cache不知道有用没,反正试了;也在添加了一句LIGHTHOUSE_CACHE_ENABLE=false)

composer require mll-lab/laravel-graphql-playground

安装了上面这个又自己写了句:php artisan vendor:publish --provider="MLL\GraphQLPlayground\GraphQLPlaygroundServiceProvider" --tag =views这样在config文件夹下面就多了个graphql-playground.php (也不知道是不是这样才解决的问题)
这个文件点开有router,所以下面可以设置

11.更改route->graphql->schema.graphal 定义type(根据自己加的Model的属性scheme挨着写全;添加Query里面要查询的关联)

type Query {
    users: [User!]! @paginate(defaultCount: 10)//默认就有可以注释
    user(id: ID @eq): User @find

    books: [Book] @all //查所有的book返回一个Book数组
    Book(id: ID @eq): Book @find //
    booksByFeatured(featured: Boolean! @eq): [Book] @all
    someComplexQuery(search: String!): [Book]
}
//添加下面两个type
type Book {
    id: ID!
    title: String!
    author: String!
    image: String
    link: String
    description: String
    featured: Boolean
    category: category! @belongsTo 
}
//这里写成了小写!!!卡了一天不知是不是这个原因
type Category {
    id: ID!
    name: String!
    books: [Book] @hasMany
}
  1. app->config->lighthouse.php更改namespace下models=>'App'去掉那个后面的'App\Models' 【去掉model】
    playground就可以查到,这样返回的数据就可以用在前端了。
query {
  category(id: 1) {
    id
    name
    books {
      title
      author
      image
    }
  }
}
  1. 如果需要自定义查询,可以在type Query里面新增
someComplexQuery(search: String!): [Book]

然后执行php artisan lighthouse:query SomeComplexQuery可以php artisan查看写法(SomeComplexQuery和schema里面要一致)然后就在app->http->GraphQL里面新创建了个SomeComplexQuery类, 然后在里面写复杂的逻辑

                    //模糊搜索wildcard,searchWord是参数
return \App\Book::where('author', 'like', '%'.$args['searchWord'].'%')->get();

去playground(http://localhost:8000/graphql-playground
⚠️后缀只写graphql返回一个error,虽然lighthouse相当于开启了一个server但是还要用xampp把数据库开启)
搜索一下:就会返回两本这个Gary的书

query {
  someComplexQuery(searchWord: "Gary") {
    author
    title
  }
}

然后把Book和Category所有的【增删改】写了,瞬间感觉后端变得巨简单!

type Mutation {               //⚠️是Mutation
    # createUser(
    #     name: String @rules(apply: ["required"])
    #     email: String @rules(apply: ["required", "email", "unique:users,email"])
    # ): User @create(model: "App\\User")
    # updateUser(
    #     id: ID @rules(apply: ["required"])
    #     name: String
    #     email: String @rules(apply: ["email"])
    # ): User @update(model: "App\\User")
    # deleteUser(
    #     id: ID @rules(apply: ["required"])
    # ): User @delete(model: "App\\User")

    createCategory(
        name: String @rules(apply: ["required", "unique:categories,name"])
    ): Category @create

    updateCategory(
        id: ID @rules(apply: ["required"])
        name: String @rules(apply: ["required", "unique:categories,name"])
    ): Category @update

    deleteCategory(
        id: ID! @rules(apply: ["required"])
    ): Category @delete

    createBook(
        title: String! @rules(apply: ["required"])
        author: String! @rules(apply: ["required"])
        image: String
        link: String
        description: String
        featured: Boolean
        category_id: Int!
    ): Book @create

    updateBook(
        id: ID @rules(apply: ["required"])
        title: String! @rules(apply: ["required"])
        author: String! @rules(apply: ["required"])
        image: String
        link: String
        description: String
        featured: Boolean
        category_id: Int!      //⚠️不知为何不能写category!!又卡2小时
    ): Book @update

    deleteBook(
        id: ID! @rules(apply: ["required"])
    ): Book @delete
}

前端https://apollo.vuejs.org/guide/apollo/queries.html#simple-query

  1. vue create booksql-vue ->多选了router 和 vuex 然后history Mode,Elint第一个error就够了,config files,OK。
    cd booksql-vue => npm run serve
  2. 刚刚那个laravel开启server的app里面添加cors依赖,因为vue在另一个port,所以防止CORS,安装插件composer require barryvdh/laravel-cors (直接goole laravel cors就看到了这个GitHub,现在是composer require fruitcake/laravel-cors)

⚠️还是要安装到booksql-laravel根目录不是vue里面!
⚠️这个库改名字了!\Fruitcake\Cors\HandleCors::class

在config->lighthouse添加middle

protected $middleware = [
    // ...
    \Fruitcake\Cors\HandleCors::class,
];

各种坑啊!!安了也说报错拿不到数据,还说我不能cors!!又耗时三个小时至少!!添加了一个新的middlewarephp artisan make:middleware Cors然后在$next下添加了三句话

   public function handle($request, Closure $next)
   {
       return $next($request)
       ->header('Access-Control-Allow-Origin', '*')
       ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
       ->header('Access-Control-Allow-Headers', 'Content-Type, Authorizations');
   }

然后在kernel.php里面注册

protected $middleware = [
        \App\Http\Middleware\Cors::class,        

妈妈咪呀,,总算拿到数据了。还有各种WebSocket connection to 'ws... '报错❌不管了~~

  1. 在前端vue文件下也安装一个graphQL的接收器 vue add apollo 然后选三个 no 往下走 [email protected]
╭─[email protected] /Applications/XAMPP/xamppfiles/htdocs/Icreate/Vue/book_shelf_vue  ‹master*› 
╰─➤  vue add apollo 

  Installing vue-cli-plugin-apollo...


> @apollo/[email protected] postinstall /Applications/XAMPP/xamppfiles/htdocs/Icreate/Vue/book_shelf_vue/node_modules/@apollo/protobufjs
> node scripts/postinstall


> [email protected] postinstall /Applications/XAMPP/xamppfiles/htdocs/Icreate/Vue/book_shelf_vue/node_modules/nodemon
> node bin/postinstall || exit 0

Love nodemon? You can now support the project via the open collective:
 > https://opencollective.com/nodemon/donate

+ [email protected]
added 354 packages from 291 contributors and audited 44468 packages in 37.989s

50 packages are looking for funding
  run `npm fund` for details

found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details
✔  Successfully installed plugin: vue-cli-plugin-apollo

? Add example code No
? Add a GraphQL API Server? No
? Configure Apollo Engine? No

  Invoking generator for vue-cli-plugin-apollo...
  Installing additional dependencies...

added 2 packages from 3 contributors and audited 44479 packages in 21.469s

50 packages are looking for funding
  run `npm fund` for details

found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details
⠋  Running completion hooks...error: Require statement not part of import statement (@typescript-eslint/no-var-requires) at apollo.config.js:1:14:
> 1 | const path = require('path')
    |              ^
  2 | 
  3 | // Load .env files
  4 | const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env')


error: Require statement not part of import statement (@typescript-eslint/no-var-requires) at apollo.config.js:4:21:
  2 | 
  3 | // Load .env files
> 4 | const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env')
    |                     ^
  5 | const env = loadEnv([
  6 |   path.resolve(__dirname, '.env'),
  7 |   path.resolve(__dirname, '.env.local')


2 errors found.

报了两个错,貌似是哦eslint和typescript的语法错误,没管。
https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-var-requires.md
中间的1 low severity vulnerability 直接按提醒走

╭─me@npm audit fix 
up to date in 8.756s

50 packages are looking for funding
  run `npm fund` for details

fixed 0 of 1 vulnerability in 44479 scanned packages
  1 vulnerability required manual review and could not be updated

然后文件目录多出 vue-apollo.jsapollo.config.js

  1. 该vue-apllo.js里面的http endpoint,选择刚刚laravel开启的后端
    http://localhost:8000/graphql'然后开始在home版面发起query测试数据是否传过来了import gql from 'graphql-tag'
  2. 在src下面新建文件夹graphql里面再建两个文件夹mutations & queries。
    在queries里面先新建Categories.gql

⚠️如果遇到 error:Parsing error:Unexpected token,expected ";" 添加一个.eslintignore 文件写上: **/*.gql 就可以去掉warning

⚠️如果遇到Failed to compile with 1 errors 然后写了Module parse failed:Uxpected token(1:6)直接删除node_modules包,然后重新npm install

图片的链接最好把path单独写在数据库里

query(ID: id) {
    book($id: ID)   //进行传参id的type就是ID
}
mutation(
    $title: String!
    $image: String!
    $featured: Boolean
    $category: Int!) {
    createBook(
    title: $title
    image: $image
    featured: $featured
    category: $category
    ) {
  }
}

自己摸索vuetify部分

  1. 用的vue ui找插件vuetify安装,也可以直接vue add vuetify在终端添加
    然后npm run serve就报错,出师未捷身先死☠️什么都没做,就报错找不到 vuetify/lib 改了vuetify-loader下面的constructor
class VuetifyLoaderPlugin {
  constructor (options) {
    // this.options = options || {}
    this.options = (options) ? options : {}
  }

https://stackoverflow.com/questions/59005933/fresh-project-fail-to-compile-after-installing-vuetify-in-vue-js#

  1. OK,开始渲染各种数据
    可以一直用tag这种写法,也可以用component,我后面还是选后者,这样可以不写script直接包含了slot的概念然后prop出来
import gql from 'graphql-tag'

  export default {
    name: "category",
    data() {
      return {
          categories: []
      }
    },
    apollo: {
        categories: gql`{
            categories {
                id
                name
            }
        }`,
    },

component模版


为了方便管理把所有的query和mutation新建一个graphql目录,然后对应放进去


屏幕快照 2020-05-05 下午5.54.41.png

⚠️出现错误


屏幕快照 2020-05-05 下午6.02.26.png

ll //查看
rm -rf node_modules //删除node_modules
npm install //再安装一遍
然后在npm run serve或者在vue UI工具里面run一遍,ok只是换了一个端口,但是数据可render出来
虽然不影响但是UI工具里面报错

6:32 Could not find a declaration file for module './vue-apollo'. '/Applications/XAMPP/htdocs/Icreate/Vue/book_shelf_vue/src/vue-apollo.js' implicitly has an 'any' type.
    4 | import store from './store'
    5 | import vuetify from './plugins/vuetify';
  > 6 | import { createProvider } from './vue-apollo'
      |                                ^
    7 | 
    8 | Vue.config.productionTip = false
    9 | 
ERROR in /Applications/XAMPP/htdocs/Icreate/Vue/book_shelf_vue/src/main.ts(13,3):
13:3 No overload matches this call.
  Overload 1 of 3, '(options?: ThisTypedComponentOptionsWithArrayProps | undefined): CombinedVueInstance>', gave the following error.
    Argument of type '{ router: VueRouter; store: Store<{}>; vuetify: any; apolloProvider: any; render: (h: CreateElement) => VNode; }' is not assignable to parameter of type 'ThisTypedComponentOptionsWithArrayProps'.
      Object literal may only specify known properties, and 'vuetify' does not exist in type 'ThisTypedComponentOptionsWithArrayProps'.
  Overload 2 of 3, '(options?: ThisTypedComponentOptionsWithRecordProps | undefined): CombinedVueInstance>', gave the following error.
    Argument of type '{ router: VueRouter; store: Store<{}>; vuetify: any; apolloProvider: any; render: (h: CreateElement) => VNode; }' is not assignable to parameter of type 'ThisTypedComponentOptionsWithRecordProps'.
      Object literal may only specify known properties, and 'vuetify' does not exist in type 'ThisTypedComponentOptionsWithRecordProps'.
  Overload 3 of 3, '(options?: ComponentOptions, DefaultMethods, DefaultComputed, PropsDefinition>, Record<...>> | undefined): CombinedVueInstance<...>', gave the following error.
    Argument of type '{ router: VueRouter; store: Store<{}>; vuetify: any; apolloProvider: any; render: (h: CreateElement) => VNode; }' is not assignable to parameter of type 'ComponentOptions, DefaultMethods, DefaultComputed, PropsDefinition>, Record<...>>'.
      Object literal may only specify known properties, and 'vuetify' does not exist in type 'ComponentOptions, DefaultMethods, DefaultComputed, PropsDefinition>, Record<...>>'.
    11 |   router,
    12 |   store,
  > 13 |   vuetify,
       |   ^
    14 |   apolloProvider: createProvider(),
    15 |   render: h => h(App)
    16 | }).$mount('#app')
ERROR in /Applications/XAMPP/htdocs/Icreate/Vue/book_shelf_vue/src/plugins/vuetify.ts(2,21):
2:21 Could not find a declaration file for module 'vuetify/lib'. '/Applications/XAMPP/htdocs/Icreate/Vue/book_shelf_vue/node_modules/vuetify/lib/index.js' implicitly has an 'any' type.
  Try `npm install @types/vuetify` if it exists or add a new declaration (.d.ts) file containing `declare module 'vuetify/lib';`
    1 | import Vue from 'vue';
  > 2 | import Vuetify from 'vuetify/lib';
      |                     ^
    3 | 
    4 | Vue.use(Vuetify);

找不到apollo就在tsconfig.json里面写了下面这两个地方
https://github.com/vuejs/vue-apollo/issues/278
Could not find a declaration file for module './vue-apollo'.

    "typeRoots": [
      "./node_modules/@types",
      "./node_modules/vuetify/types",
      "./node_modules/vue-apollo/types"
    ],

    "types": [
      "webpack-env",
      "vuetify",
      "vue-cli-plugin-apollo/types"
    ],

添加新的页面Book.vue
在router下面的index.ts下面注册

  {
    path: '/book/:id',
    name: 'Book',
    component: () => import(/* webpackChunkName: "about" */ '../views/Book.vue')
  }

在App.vue下面是根目录入口点 http://localhost:8080/book/1

    
         这样就是加载component里面的组件
            这样就是用每个view下面单独的vue文件
    
import category from './views/Category.vue';  如果用view下面单独文件这个可以不用写

加fontawesome图标引用,放在public下面index.html里面cnd

麻烦还注册然后给了一串自己的编号

可以用vue-apollo.js里面控制记录token, 存在localstorage里面,退出登录销毁

// Manually call this when user log in
export async function onLogin (apolloClient, token) {
  if (typeof localStorage !== 'undefined' && token) {
    localStorage.setItem(AUTH_TOKEN, token)
  }
  if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
  try {
    await apolloClient.resetStore()
  } catch (e) {
    // eslint-disable-next-line no-console
    console.log('%cError on cache reset (login)', 'color: orange;', e.message)
  }
}

// Manually call this when user log out
export async function onLogout (apolloClient) {
  if (typeof localStorage !== 'undefined') {
    localStorage.removeItem(AUTH_TOKEN)
  }
  if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
  try {
    await apolloClient.resetStore()
  } catch (e) {
    // eslint-disable-next-line no-console
    console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
  }

报错❌
Cannot read property 'freezeResults' of null
https://github.com/vuejs/vue-apollo/issues/631
只需要在vue-apollo.js里面把cache

import { InMemoryCache } from 'apollo-cache-inmemory';

const defaultOptions = {
 // Override default cache
 cache: new InMemoryCache(),

}

你可能感兴趣的:(booksql-laravel)