アプリ関連ニュース

Laravel + Vue JS CRUD Single Page Applicationの作成

今回は、LaravelとVue JSを使ったSingle Page Applicationの作成方法についてご案内します。

ここでは、セットアップに必要な手順を説明します。

このコマンドでLaravelのプロジェクトを新規に作成する必要があります。

composer create-project laravel/laravel --prefer-dist laravel-vue

次に、プロジェクトの.env configファイルにデータベース名、ユーザー名、パスワードを追加して、データベース接続を行う必要があります。

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_vue
DB_USERNAME=root
DB_PASSWORD=

LaravelでArticleモデルを作成するには、以下のコマンドを実行してください。

php artisan make:model Article -m

database/migrations/create_articles_table.php に以下のコードを追加してください。

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('artcles', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('descriptions');            
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

マイグレーションを呼び出すには、以下のコマンドを実行してください。

php artisan migrate

記事コントローラを作成

記事コントローラを作成し、CRUD操作のメソッドを定義する必要があります

php artisan make:controller ArticleController

Article Controllerを以下のコードで更新します。

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Article;
class ArticleController extends Controller
{
    public function index()
    {
        $articles = Article::all()->toArray();
        return array_reverse($articles);      
    }
    public function store(Request $request)
    {
        $article = new Article();
        $article->title = $request->input('title');
        $article->description = $request->input('description');
        $article->save();

        return response()->json('New Article is successfully created!');
    }
    public function show($id)
    {
        $article = Article::find($id);
        return response()->json($article);
    }
    public function update($id, Request $request)
    {
        $article = Article::find($id);
        $article->title= $request->title;
        $article->description = $request->description;
        $article->save();

        return response()->json('Article is successfully updated!');
    }
    public function destroy($id)
    {
        $article = Article::find($id);
        $article->delete();
        return response()->json('Article is successfully deleted!');
    }
}

routesのweb.phpとapi.phpを更新してください。

routes/web.php

<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
*/
 
Route::get('{any}', function () {
    return view('app');
})->where('any', '.*');

routes/api.php

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ArticleController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
*/
Route::middleware('api')->group(function () {
    Route::resource('articles', ArticleController::class);
});

laravel/ui composer パッケージをインストールします。

composer require laravel/ui

次に、Vueの足場を設定します。

laravel/uiパッケージには、Vueを使い始めるために必要なすべてのものを自動的に足場にしてくれる便利なArtisanコマンドがいくつか用意されています。

php artisan ui vue

ファイルをコンパイルする

最後に、新しく追加された依存関係をインストールして、コンパイルする必要があります。

npm install && npm run dev

コマンドを使用して、vue router および vue axios パッケージをインストールします。

npm install vue-router vue-axios

次に、npm パッケージをインストールし、アセットをコンパイルするために、次のコマンドを実行します。

npm install
npm run watch

LaravelでVueを開始する

layoutフォルダを作成し、このフォルダ内にapp.blade.phpを作成してアプリケーションを設定する必要があります。

resources/views/layout/app.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" value="{{ csrf_token() }}" />
    <title>Vue JS CRUD Operations in Laravel</title>
    <link href="{{ mix('css/app.css') }}" type="text/css" rel="stylesheet" />
</head>
<body>
    <div id="app"></div>
    <script src="{{ mix('js/app.js') }}" type="text/javascript"></script>
</body>
</html>

App.vue ファイルに router-view 命令を追加する必要があります。そこで、resources/js フォルダに App.js ファイルを作成します。

resources/js/App.js

<template>
    <div class="container"> 
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <div class="collapse navbar-collapse">
                <div class="navbar-nav">
                    <router-link to="/" class="nav-item nav-link">Articles List</router-link>
                    <router-link to="/create" class="nav-item nav-link">Create Article</router-link>
                </div>
            </div>
        </nav>
        <router-view> </router-view>
    </div>
</template>
 
<script>
    export default {}
</script>

そして、resources/js/componentsフォルダの中に必要なvue jsコンポーネントファイルを作成します。

resources/js/components/AllArticle.vue

<template>
    <div>
        <h2 class="text-center">Article List</h2>
 
        <table class="table">
            <thead>
            <tr>
                <th>ID</th>
                <th>Title</th>
                <th>Desciption</th>
                <!-- <th>Actions</th> -->
            </tr>
            </thead>
            <tbody>
            <tr v-for="article in articles" :key="a.article">
                <td>{{ article.id }}</td>
                <td>{{ article.title }}</td>
                <td>{{ article.description}}</td>
                <td>
                    <div class="btn-group" role="group">
                        <router-link :to="{name: 'edit', params: { id: article.id }}" class="btn btn-success">Edit</router-link>
                        <button class="btn btn-danger" @click="deleteArticle(article.id)">Delete</button>
                    </div>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
</template>
 
<script>
    export default {
        data() {
            return {
                articles: []
            }
        },
        created() {
            this.axios
                .get('http://localhost:8000/api/articles/')
                .then(response => {
                    this.articles = response.data;
                });
        },
        methods: {
            deleteArticle(id) { 
                this.axios
                    .delete(`http://localhost:8000/api/articles/${id}`)
                    .then(response => {
                        let i = this.articles.map(data => data.id).indexOf(id);
                        this.articles.splice(i, 1)
                    });
            }
        }
    }
</script>

resources/js/components/CreateArticle.vue

<template>
    <div>
        <h3 class="text-center">Create Article</h3>
        <div class="row">
            <div class="col-md-6">
                <form @submit.prevent="addArticle">
                    <div class="form-group">
                        <label>Title</label>
                        <input type="text" class="form-control" v-model="article.title">
                    </div>
                    <div class="form-group">
                        <label>Description</label>
                        <input type="text" class="form-control" v-model="article.description">
                    </div>
                    <button type="submit" class="btn btn-primary">Create</button>
                </form>
            </div>
        </div>
    </div>
</template>
 
<script>
    export default {
        data() {
            return {
                article: {}
            }
        },
        methods: {
            addArticle() {
                this.axios
                    .post('http://localhost:8000/api/articles', this.article)
                    .then(response => (
                        this.$router.push({ name: 'home' })
                    ))
                    .catch(err => console.log(err))
                    .finally(() => this.loading = false)
            }
        }
    }
</script>

 resources/js/components/EditArticle.vue

<template>
    <div>
        <h3 class="text-center">Edit Article</h3>
        <div class="row">
            <div class="col-md-6">
                <form @submit.prevent="updateArticle">
                    <div class="form-group">
                        <label>Title</label>
                        <input type="text" class="form-control" v-model="article.title">
                    </div>
                    <div class="form-group">
                        <label>Detail</label>
                        <input type="text" class="form-control" v-model="article.description">
                    </div>
                    <button type="submit" class="btn btn-primary">Update</button>
                </form>
            </div>
        </div>
    </div>
</template>
 
<script>
    export default {
        data() {
            return {
                article: {}
            }
        },
        created() {
            this.axios
                .get(`http://localhost:8000/api/articles/${this.$route.params.id}`)
                .then((res) => {
                    this.article = res.data;
                });
        },
        methods: {
            updateArticle() {
                this.axios
                    .patch(`http://localhost:8000/api/articles/${this.$route.params.id}`, this.article)
                    .then((res) => {
                        this.$router.push({ name: 'home' });
                    });
            }
        }
    }
</script>

vueのルートを作成するには、resources/jsディレクトリの中にroutes.jsを作成します。

resources/js/routes.js

import AllArticle from './components/AllArticle.vue';
import CreateArticle from './components/CreateArticle.vue';
import EditArticle from './components/EditArticle.vue';
 
export const routes = [
    {
        name: 'home',
        path: '/',
        component: AllArticle
    },
    {
        name: 'create',
        path: '/create',
        component: CreateArticle
    },
    {
        name: 'edit',
        path: '/edit/:id',
        component: EditArticle
    }
];

最後にVue App.jsを定義します。

 resources/js/app.js

/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */
require('./bootstrap');
window.Vue = require('vue');
import App from './App.vue';
import VueAxios from 'vue-axios';
import VueRouter from 'vue-router';
import axios from 'axios';
import { routes } from './routes';
/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */
Vue.use(VueRouter);
Vue.use(VueAxios, axios);
 
const router = new VueRouter({
    mode: 'history',
    routes: routes
});
 
const app = new Vue({
    el: '#app',
    router: router,
    render: h => h(App),
});

アプリを起動するには、以下の2つのコマンドを実行します。

npm run watch
php artisan serve

ブラウザで http://127.0.0.1:8000 にアクセスすると、記事の一覧表示、記事の作成、更新ができます。

この記事があなたのお役に立てれば幸いです。

By Tsuki



2022-03-08 AppleEvent開催!

昨日(2022-03-08)にAppleEventが開催されました。
新製品が発表されましたので感想をシェアしたいと思います。

続きを読む

Useful Features of Rsync Command in Linux

Today, I would like to share about usefulness of rsync command in Linux and how to back up data with cron job. Let’s take a look.

Rsync (Remote Sync) is the most commonly used command for copying and synchronizing files and directories remotely as well as locally in Linux/Unix systems. Data can be copied, synchronized and backup both remotely and locally across directories, disks & networks.

Advantages of Rsync Command

  • It efficiently copies and sync files from source to destination remotely or locally.
  • It supports copying links, devices, owners, groups and permissions.
  • rsync allows to transfer just the differences between source and destination. The first time, it copies the whole content of a file or a directory from source to destination but from next time, it copies only the changed files/data to the destination.
  • Due to using compression and decompression method while transferring data, rsync consumes less bandwidth.

Installing Rsync

rsync is preinstalled on most Linux distributions and mac-OS. If rsync hasn’t been installed on the system, it can be installed easily using your distribution’s package manager as follows.

$ sudo apt-get install rsync [On Debian/Ubuntu & Mint]

$ pacman -S rsync [On Arch Linux]

$ emerge sys-apps/rsync [On Gentoo]

$ sudo dnf install rsync [On Fedora/CentOS/RHEL and Rocky Linux/AlmaLinux]

$ sudo zypper install rsync [On openSUSE]

Rsync Basic Command Syntax

Local to Local

rsync [OPTION] [SRC] [DEST]

Local to Remote

rsync [OPTION] [SRC] [USER@]HOST:DEST

Remote to Local

rsync [OPTION] [USER@]HOST:SRC [DEST]

Common options[OPTION] used with rsync commands

-v : verbose

-r : copies data recursively (but don’t preserve timestamps and permission while transferring data.

-a : archive mode, which allows copying files recursively and it also preserves symbolic links, file permissions, user & group ownerships, and timestamps.

-z : compress file data.

-h : human-readable, output numbers in a human-readable format.

For more options, the following command can be used.

$ rsync -h

For example, to backup data from local to local(external hard drive), the following command is commonly used.

rsync -azv /home/username/projects /media/username/SPHardDrive/BackupFolder

Schedule backups

To enable scheduled backups, cron can be used for the rsync commands.

Conclusion

This is all how to copy, synchronize and backup files & directories. And I recommend the link to learn more about rsync.

Hope you enjoy that.

By Asahi



Apple’s March 8 event

The next Apple event is Tuesday, March 8th. This will be a virtual event that can also be viewed from Apple’s website or Apple TV and YouTube. Today I gonna share with you some rumors expectations for this coming event.

New iPhone SE

Every few years, Apple releases a low-priced iPhone with the latest components in its old body, and this year is no exception. Apple plans to launch a third iPhone SE for $ 399, with the same iPhone 6-like design as before, but with 5G support, an improved camera, and an A15 Bionic processor.

iPhone SE
Credit: thenextweb

iPad air 5

New year, new iPad. The iPad will be equipped with an A15 chip, two additional speakers (four in total), and a 5G connection. The camera may also be improved.

Mac mini

Apple plans to announce a number of Macs this year, with at least one likely to be seen at the March 8 event. The catchphrase “Peak Performance”; and the direction is that Apple usually won’t launch high-performance mobile products until the fall.

Rumor has it that the “Mac Mini Pro” with M1 Max and M1 Pro chips is now being pointed out. After all, it doesn’t make sense for Apple laptops to be stronger than desktop products for a long time. This Mac Mini is expected to offer a slimmer and more sophisticated design.

New MacBook with M2

Apple’s M1 chip was announced in 2020. That is, you are trying to get an update. Rumor has it that the new MacBook Pro with an entry-level M2 chip should be better than the previous M1 MacBook Pro, but it doesn’t quite match the M1 Pro or Max.

To keep costs relatively low, the new MacBook Pro doesn’t have a flashy 120Hz display or Mini LED panel. The benefit of inferior screen technology is that it can avoid the dreaded notch, perhaps.

It’s also very likely that Apple will announce a redesigned MacBook Air with an M2 chip later this year, but it’s not sure.

iOS 15.4

On the software side, we are planning a release date for iOS 15.4. This is primarily a mid-cycle update and primarily includes Face ID support while wearing a mask. It also includes over 30 new emojis, non-binary Siri voice, and support for multi-device interaction with Universal Control. But most of the software might come at WWDC later this year.

Yuuma



Laravelのファイルアップロード: 重複するファイル名 – 解決するための2つの方法

今日は、ファイルのアップロードについて、特に、同じファイル名でファイルをアップロードできるようにするとどうなるか、古いファイル名を上書きしてしまうか、それをいろいろとお話したいと思います。

例えば、デフォルトで登録フォームがあり、アバターがあり、誰かがavator.jpgというファイル名でファイルをアップロードしたとします。これは正常にアップロードされているのですが、開発者がよくやるのは、ClientOriginalNameが悪意のないものであることを信じてファイル名をアップロードすることです。
しかし、元のファイル名を保持したい場合は、それは大丈夫かもしれません。しかし、同じファイル名で登録した人がいて、そのファイルがstorage/app/public/avatorsにavator.jpgとしてアップロードされた場合、問題が発生することがあります。

そして、別のユーザーで登録しようとし、ユーザー情報を入力し、異なるパスからアバターをアップロードしますが、ファイル名は同じです。登録後、古いアバターはやみくもに上書きされ、サーバーから削除されることさえあります。というわけで、これは今問題になっています。どのようにコードでそれを解決するかは、いくつかの異なる方法があります。

ということで、今からこの方法をお話ししたいと思います。

1つ目はファイル名を変更する方法です。

if ($request->file('avatar')) {
            $fileName = pathinfo($request->file('avatar')->getClientOriginalName(), PATHINFO_FILENAME) . '-' . $user->id . '.' . $request->file('avatar')->getClientOriginalExtension();

            $request->file('avatar')->storePubliclyAs('avatars', $fileName, 'public');

            $user->update([
                'avatar' => $fileName ?? null,
            ]);
        }

アベータがある場合、拡張子なしのファイル名からファイルを作成し、ユーザ登録からuser_id、そしてオリジナルの拡張子からファイルを構築することになります。そして、そのファイルをファイル名と一緒にパブリックドライバに保存し、ユーザを更新します。

2つ目はサブフォルダを作成する方法です。

$request->file('avatar')->storePubliclyAs("avatars/{$user->id}", $request->file('avatar')->getClientOriginalName(), 'public');

publicのuser_idサブフォルダに元のファイル名で保存します。

結果一覧

はい。ということで今回は以上になります。

By Ami



アプリ関連ニュース

お問い合わせはこちら

お問い合わせ・ご相談はお電話、またはお問い合わせフォームよりお受け付けいたしております。

tel. 06-6454-8833(平日 10:00~17:00)

お問い合わせフォーム