4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

qnoteAdvent Calendar 2022

Day 18

【Laravel】Backlogから課題を取得してcsvで出力する方法

Last updated at Posted at 2022-12-17

はじめに

さて、今年のアドベントカレンダーは何を書こうかと、、、。
ちょうどLaravelでBacklogとNotionを連携する処理を書いていたので、それ関連で書こうと考えた。
本当はNotionに連携するところまで書こうと思っていたのだが、
まだ実装途中で時間がかかりそうなので、
Backlogから値を取得してcsvで出力するまでの記事を書くことにした。
プロジェクトの情報が漏洩しないように、外部の情報は、サニタイズして記述するので、
動かなかったらごめん🙇‍♀️

対象読者

  • Web系エンジニアの人
  • プログラミングやってる人
  • Laravelやってる人
  • Backlog使ってる人

backlogとは?

チームのタスク管理ツールのこと。
URL:https://backlog.com/ja/

大まかな手順

  1. Laravel環境構築
  2. League\Csvのインストール
  3. BacklogAPIキーの取得
  4. 実装

Laravel環境構築

使用技術

※ MySqlは現在は使われていないが、今後使用するかもしれないので、一応入れておく。

Name version
PHP 8.1.12
Laravel 9.41.0
Laravel-sail 8.1
MySql 8.0
League/csv 9.8

とりあえずsailで環境構築。csvはLeague/csvで出力する。

事前準備

  • Docker Desktop (Docker for Mac) をインストールしておく
    公式:https://www.docker.com/products/docker-desktop/

  • 手元のマシンに php@8.1 と composer 2.x を入れておく
    brewでインストールするのが早い(brewのインストールとかは抜粋します。)

$ brew install php@8.1
$ brew install composer

1. 任意のディレクトリでLaravelアプリケーションを作成する

example-appの箇所は任意のプロジェクト名を入れる

$ curl -s "https://laravel.build/example-app" | bash

2. ディレクトリを移動して、sailを立ち上げる

$ cd example-app

$ ./vendor/bin/sail up

エイリアスを作成すると下記だけでいける。

$ sail up -d

エイリアスの設定の仕方

bashの場合 → .bashrc
zshの場合 → .zshrc
.bashrcか、.zshrcに下記を記述する

.zshrc
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'

4. docker-compose.ymlを修正する

使わないサーバーを削除(mysqlは使用しないがなんとなく残している)

docker-compose.yml
# For more information: https://laravel.com/docs/sail
version: '3'
services:
    app:
        build:
            context: ./vendor/laravel/sail/runtimes/8.1
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.1/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80'
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
    mysql:
        image: 'mysql/mysql-server:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ROOT_HOST: "%"
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 1
        volumes:
            - 'sail-mysql:/var/lib/mysql'
            - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
        networks:
            - sail
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
            retries: 3
            timeout: 5s
networks:
    sail:
        driver: bridge
volumes:
    sail-mysql:
        driver: local

servicesの名前を変更したので、.envにAPP_SERVICE="app"を記述。

.env
APP_SERVICE="app"

ymlファイルを変更したので、sailを立ち上げ直す

$ sail down
$ sail up -d

League\Csvのインストール

インストール

$ composer require league/csv

BacklogAPIキーの取得

バックログにログインして、
Backlog > 個人設定 > APIにて、わかりやすいメモを記入し発行ボタンを押して、
APIキーを発行します。
(本当はスクショして見せようかと思ったのですが、社内情報が漏れるのが怖いので、文字だけで勘弁。)

実装

1..envにAPIKEYを記述する

.env
BACKLOG_API_KEY=${取得したAPIKEY}

2.config配下にbacklog.phpを作成する

config/backlog.php
<?php

return [
    'base_uri' => ${プロジェクトのURL},
    'api_key' => env('BACKLOG_API_KEY'),
    'project_id' => ${プロジェクトのID},
];

3.今回はバッチ処理のなので、config/filesystem.phpにbatchを追加する

config/filesystem.php
'batch' => [
            'driver' => 'local',
            'root'   => storage_path('app/batch'),
        ],

4. app/Console/Commands配下にバッチ処理を作成する

ImportAndExportCsvBacklog.php
<?php

namespace App\Console\Commands;

use App\Actions\ExportBacklogCsv;
use App\Actions\GetBacklogDatas;
use Illuminate\Console\Command;

class ImportAndExportCsvForEvmsBacklog extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'import-and-export-csv-for-backlog';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'バックログ取り込み・CSV出力バッチ';

    /**
     * Execute the console command.
     */
    public function handle(GetBacklogDatas $getBacklogDatas, ExportBacklogCsv $exportCsv)
    {
        $this->info('開始');

        $baseUri = config('backlog.base_uri');

        try {
            // バックログにAPIを投げて値を取得
            $backlogDatas = $getBacklogDatas->exec($baseUri);

            // csvに出力
            $exportCsv->exec($backlogDatas, $baseUri);
        } catch (\Exception $e) {
            $this->info($e);
        }

        $this->info('終了');
    }
}

処理は下記のクラスに分けました。

GetBacklogDatas → バックログから値を引っ張ってくるクラス
ExportBacklogCsv → データをCSVに吐き出すクラス

5. app/Actions/GetBacklogDatasを作成する

今回は課題の一覧を取得したかったので、下記を使用します。

条件

ステータスは、未対応、処理中、処理済で絞る
課題は100件以上ないことを前提に処理を組んでいる(backlogのAPIは一度に100件しかデータが取れないため。)
GetBacklogDatas.php
<?php

namespace App\Actions;

use Illuminate\Support\Facades\Http;

class GetBacklogDatas
{

    private const NO_COMPATIBLE = 1; // 未対応
    private const PROCESSING = 2; // 処理中
    private const PROCESSED = 3; // 処理済

    /**
     * exec
     * @param string $baseUri
     * @return array
     */
    public function exec($baseUri): array
    {
        $apiKey = config('backlog.api_key');

        $params = $this->getParams($apiKey);

        $response = Http::get("$baseUri/api/v2/issues", $params);

        return $response->json();
    }

    /**
     * getParams
     * @param string $apiKey
     * @return array
     */
    protected function getParams(string $apiKey): array
    {
        /**
         * backlogのAPIが1回に100件しか値を取れないので、
         * それ以上取得する場合は、offsetをうまく利用した実装に変更する必要があるが、
         * 一旦は100件を超えることは考えにくいため、そのままとする
         */
        return [
            'apiKey' => $apiKey,
            'projectId[]' => config('backlog.project_id'),
            'statusId[]' =>  self::NO_COMPATIBLE,
            'statusId[1]' => self::PROCESSING,
            'statusId[2]' => self::PROCESSED,
            'count' => 100,
        ];
    }
}

6. ExportBacklogCsvを作成する

League/csvを使用して出力する

条件

課題名、担当者、期日、のデータを出力する
ExportBacklogCsv.php
<?php

namespace App\Actions;

use Carbon\Carbon;
use Illuminate\Support\Facades\Storage;
use League\Csv\CharsetConverter;
use League\Csv\Writer;

class ExportBacklogCsv
{
    protected string $inputEncode = 'UTF-8';
    protected string $outPutEncode = 'SJIS-win';
    protected string $disk = 'batch';
    protected string $uri;
    protected array $backlogDatas;

    /**
     * exec
     * @param array $backlogDatas
     * @param string $uri
     */
    public function exec(array $backlogDatas, string $uri)
    {
        $this->uri = $uri;
        $this->backlogDatas = $backlogDatas;
        $this->exportCsv($backlogDatas);
    }

    /**
     * exportCsv
     */
    protected function exportCsv()
    {
        [$header, $records] = $this->getHeaderAndRecords();

        // エンコーディングの設定
        $converter = (new CharsetConverter())
                ->inputEncoding($this->inputEncode)
                ->outputEncoding($this->outPutEncode);

        $csv = Writer::createFromString()
            ->addFormatter($converter);

        // Headerの作成
        $csv->insertOne($header);

        // Recodeの作成
        $csv->insertAll($records);

        if (Storage::exists($this->disk)) {
            Storage::makeDirectory($this->disk);
        }

        $nowFormat = Carbon::now()->format('YmdHis');

        $fileName = "backlog_issue/backlog_issue_$nowFormat.csv";

        // ファイルの生成
        Storage::disk($this->disk)->put($fileName, '');

        // ファイルパスの取得
        $path = Storage::disk($this->disk)->path($fileName, true);

        // ファイルに記述
        file_put_contents($path, $csv);
    }

    /**
     * getHeaderAndRecords
     * @return array
     */
    protected function getHeaderAndRecords(): array
    {
        $header = [
            '課題名',
            '担当者',
            '期日',
        ];

        foreach ($this->backlogDatas as $data) {
            $records[] = [
                $data['summary'] ?? '', // 課題名
                $data['assignee']['name'] ?? '', // 担当者
                $data['dueDate'] // 期日
                    ? Carbon::parse($data['dueDate'])->format('Y/m/d')
                    : '',
            ];
        }

        return [$header, $records];
    }
}

7. バッチを実行してみる

$ sail artisan import-and-export-csv-for-backlog

storage/app/batch/backlog_issue配下にファイルが出力されるはず!

中身はこんな感じ!
スクリーンショット 2022-12-13 19.42.14.png

まとめ

とりあえずこれで動いた。
作ってから、記事にしたので、この通りやっても動かなかったらごめん。。。
良いお年を。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?