Mi in progress

研究者の道ではなく、エンジニアになることを決意した人のブログ。

業務を通じてレイヤー化アーキテクチャを学んだ話

どうもこんにちは。

気づけば年末の振り返りから1ヶ月経ってしまいました...もっとブログを書く習慣を付けたいです。

さて、今回のテーマはレイヤー化アーキテクチャについてのお話です。

前々スプリントで実装した案件が、非常に学びが多いものだったのでブログに載せることにしました。

 

どんな案件だったのか

扱った案件をそのまま書く訳にはいかないので、今回は架空のサービスを考えます。

それは、恋活マッチングサービスです。

仮に、えんむすびという名前を付けましょう。

えんむすびでは、会員は自分のプロフィールを書くことができ、異性の会員はそれを閲覧することができます。しかしながら、このような恋愛に関するサービスではイカガワシイ人物の影が潜むものです。

怪しげな外部サイトへの誘導、イカガワシイ誘い文句などなど...健全なプラットフォームを脅かす会員を根こそぎブロックするべく、会員のプロフィールは審査員がチェックしています。


f:id:mi_progress_oOo:20180204225234p:plain

えんむすび(仮)の概要

そんな中、審査員の方から次のような依頼を受けました。 

審査員「会員様のプロフィールを審査するときに、禁止ワードをハイライトさせる機能をつけて欲しいです。それから、禁止ワードの追加・削除が気軽にできるようになりませんかね...」

私「なるほど。確かに今の仕様だと、禁止ワードの追加や削除は直接エンジニアがSQLを叩くしかないですもんね。ハイライト機能のついでに、追加や削除を審査員の方ができるようにしましょう!」 

 

要件定義

審査員の方からの要望を元に、上司や先輩からアドバイスを頂きながら次のような要件定義をしました。

 1)禁止ワードの登録・削除・検索ができる専用の画面を作成する

 2)禁止ワードの登録・削除・検索は、RDSを参照する

 3)会員のプロフィールを審査で表示する際、禁止ワードが存在していた場合はそのワードをハイライトさせる

 4)ハイライト時の禁止ワードは、RDSではなくRedisを参照する

 5)Redisの禁止ワードは寿命24時間のキャッシュとし、期限切れの際はRDSのデータを新たにセットする

 

実装してみた

早速何も考えずに実装してみました。

それがこちらです。今見ると目を覆いたくなる酷い実装です...。


f:id:mi_progress_oOo:20180204225244p:plain

修正前の実装

RDSとRedisに関する処理をLogicというクラスにひとまとめにしているのが酷いです。

さらに、要件5)を満たすための業務ロジックの中で、RDSとRedisのORマッパーが一緒に呼び出されているという悪夢のようなメソッドを生み出していました。

Redisの世界にRDSへの依存ができてしまっていたのです。

 

修正してみた

そこでLogicをRDS用とRedis用に分けた修正版がこちらになります。


f:id:mi_progress_oOo:20180204225248p:plain

修正後の実装

要件5)の部分は、赤色のActionで実装しました。

これで、少なくともRDSの世界とRedisの世界は分けられたのですが...(実際に実装したのはここまでです)

レイヤー化アーキテクチャにするとしたらどう書けるんだろう?

という興味が沸々と湧いてきたので、 DDDやクリーンアーキテクチャの勉強も兼ねて、レイヤー化を考えてみることにしました。 

 

レイヤー化アーキテクチャとは

色々な記事を読んで、レイヤー化にも様々な手法があることを学んだのですが、Spring MVCアーキテクチャが一番今回の案件に適していると感じました。実際に書いてみたのがこちらです。


f:id:mi_progress_oOo:20180204225251p:plain

レイヤー化された実装

主にこの2つの記事が参考になりました。

2.4. アプリケーションのレイヤ化 — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.3.1.RELEASE documentation

MVC の Model 肥大化への対処 - Qiita

これらを読んでいて、今回の案件はLogicをRepository(ドメイン層)とRepositoryImpl(インフラストラクチャ層)の2つに分けたほうがいいことに気がつきました。

というのも、使用するDBサーバーやORマッパーを柔軟に変えたいと思った時に、あまり業務ロジックと関わって欲しくないからです。

インターフェイスというのは規格という意味で、その実態がどのように実現されているかどうかは、ドメイン層は知らなくていい」

ということを以前教わったのですが、ようやくその意味を深く理解できるようになりました。「DBサーバーとこんなやりとりをします」という決まり事だけRepositoryに書いて、ORマッパーを使った実装はRepositoryImplに書けば良いのです。

そうすれば、「今度はMySQLじゃなくて、PostgreSQLにしよう」となったときも、DBサーバーとのやりとりは書かれているので、安心してRepositoryImplだけを変更することができます。これは、ドメイン層にとっても優しいし、エンジニアの同僚にとっても優しい仕様だと感じました。

 

ついでにPlantUMLも使ってみた

せっかくなのでクラス図の練習をしたいと思い、PlantUMLを使ってレイヤー化した際のクラス図を作ってみました。

ControllerとRepositoryImplの中身は省略しました。


f:id:mi_progress_oOo:20180204225254p:plain

PlantUMLを使ったクラス図

ついでにコードも載せますね。

@startuml

skinparam class {
    BackgroundColor #FFFBF2
    ArrowColor #1253A4
    BorderColor #FFB600
}

interface NgWordRepository {
    NgWord createNgWord(NgWord ngWord);
    void deleteNgWord(Long NgWordId);
    List<NgWord> selectNgWords(NgWordType type);
    boolean existsNgWords(NgWord ngWord);
}

interface NgWordCacheRepository {
    List<NgWord> selectNgWords(NgWordType type);
    void setNgWords(List<NgWord>);
    boolean existsNgWords(NgWord ngWord);
}

class NgWordRepositoryImpl
class NgWordCacheRepositoryImpl

class NgWordService {
    NgWord createNgWord(NgWord ngWord);
    void deleteNgWord(Long NgWordId);
    List<NgWord> fetchNgWordCache(NgWordType type);
}

class NgWordController {
}

NgWordRepository <|..NgWordRepositoryImpl
NgWordCacheRepository <|..NgWordCacheRepositoryImpl
NgWordService ..> NgWordRepository
NgWordService ..> NgWordCacheRepository
NgWordController ..> NgWordService

@enduml

PlantUMLの使い方はこちら3つのサイトが参考になりました。

Open-source tool that uses simple textual descriptions to draw UML diagrams.

PlantUML Cheat Sheet - Qiita

PlantUML を便利に使うための3つの Tips - Qiita

 

まとめ

今回業務で2つのDBサーバーを使う案件を実装したことで、レイヤー化アーキテクチャの利点を理解することができました。

百聞は一見に如かずならぬ、百見は一実装に如かずだなと。

どんなに本や記事を見ても、自分で実装するまでその大切さはわかないことを学びました。

もちろん、知っていなければわかる以前の問題なので、本や記事でのキャッチアップは重要です。これからもっともっと読まなきゃです。

でも、同じくらいコードを書かなきゃだめだなとも思いました。

読み書きに励んでいきます。

今年の振り返り

今年もあと一時間を切ったので簡潔に振り返る。

 

1月 ~ 3月

2つのバイト先を掛け持ちしていて、一方ではイベントを開催(研究者向けのクラウドファンディングをリアルでやってみた)したり、一方では訪問看護系の方々に取材に行って記事を書いたりしていた。

Progateを鬼のようにやっていた。(レベル300超えになり、会社の先輩方に「レベル300超えの子」と覚えられていた)

休学していた大学に退学届けを出しに行った。教授陣の所に行く(やめるには簡単な面談が要る)のは結構しんどかったけど、研究者の道ではなくエンジニアの道に進もうと思った決意は揺るがなかった。改めてその頃の決意を振り返ると、

 

1.研究費をもらって研究をし始めて、「直接人の役に立たない研究でお金を貰う」ことにひどく罪悪感を抱くようになった。私にとって化学は、知的好奇心を探求するための純粋な学問であり、自然と対話したくてやっているのであり、人のためにするものではなかった。

2.高校時代に、自分が作った手作り放電管キットが中学高校の先生方に評価され「これ私も作っていいですか?」と言われてものすごく嬉しかったことを思い出し、「やっぱり誰かの役に立つものが作りたい、誰かの役に立つものが作れるのが嬉しい」と感じる自分に気がついた。

3.エンジニアの友達がPC1つで様々なプロダクトを作っているのを見て、「化学者は実験室が無いと仕事ができないけど、エンジニアはPCさえあれば、家でも職場でもカフェでも仕事ができるんだな」と驚き、強烈な憧れを頂くようになった。

4.とにかくコーディングが楽しくて仕方がなかった。

5.博士号を生半可な気持ちで取る気は全くなかった。二兎を追う者は一兎をも得ず。エンジニアになりたいと決めたんだから、全力でそちらに振り切ろうと思った。

 

という感じだった。

3月の中旬に就職先から本が届けられ、Javaの本をもりもりやっていた。

 

4月

入社。全体研修と座学メインの研修。

 

5月, 6月

HTTPサーバー研修。

「サーバーって作れるの...?」「サーバーって何...?」と超不安になったのをよく覚えてる。二次情報禁止・見ていいのはオラクル公式サイトとRFCのみという制約の中で、一番最初の課題でソケットについて必死になって調べたなぁ。

自作サーバーでブラウザに文字や写真を描画できるようになった驚きと喜びは忘れられない経験になった。すごく嬉しかった!

この頃Rustに出会った。

 

7月, 8月

事業部に配属になり、Twitter研修。

「知ってるフレームワークRailsのみ」な状態で、Spring boot, Flyway, Hibernateという摩訶不思議なものたちを前に死にそうになりながらTwitterを作った。奇跡だと思う。なんで作れたのか自分でもわからない。ものすごく力が付いた課題だった。

詳しく書きたいけど時間が...

 

9月, 10月, 11月, 12月

仕事が始まる。ここも詳しく書きたいけど時間が....

自分のプロダクトで喜んでくれる人がいて、それがすごくすごく嬉しくて、「やっぱりエンジニアになってよかった」と心から思う瞬間がたくさんあった。

自分の決意は間違ってなかったと思った。

 

( ゚д゚)ハッ!もう新年だ!

明けましておめでとうございます。

今年もよろしくお願いします。

 

学びことが多すぎて何から手を出していいのかわからない状況を打破したい

 

最近の課題感

お久しぶりです。 

前回のTwitter課題修正プロジェクトからまたしても時間が空いてしまいました...

それには、最近学びたいことが多すぎて何から手を出していいのかわからない状況が続いているという背景があります。

予定のない土日はとりあえず家に引きこもって参考書を読んだりコーディングしたりしていたのですが...正直その時思いついたことベースで勉強しちゃってます。なのでブログ更新もおざなりになっていました。 

エンジニアになる夢を叶えることができて夢心地な反面、どうすれば成長していけるのか、どんなキャリアを歩んでいけばいいのか、漠然とした不安があり、手当たり次第勉強しているという状況です。とにかく暇な時はプログラミングに関係することを優先順位を付けることなくやってました。これがいけなかった。

実はこれ、単純に勉強方法としてダメなだけでなく、イベントや遊びの予定を立てるのにも悪影響を及ぼしていることに気がつきました。

「イベントに行くより家に引きこもって勉強しよう」

みたいな強迫観念が己の中に生み出されるのです。

  

解決策

というわけで手始めに、

 ・なりたい像を明確にし、そこに向けて学ぶことに優先順位を付ける

 ・学んだことを記事としてまとめておく

をしようと思いました。というのも、ふわふわしているときって大抵、

 ・ゴールを明確にしていない (どこに向かえばいいのかわからない、行動指針がないので行動できない)

 ・現状の記録や振り返りができていない (ゴールという大きな山があったとして、今何合目に自分がいるのか認識できていない)

だと思うので。

 

特に現状の振り返りは見逃されがちではないでしょうか?

私はついつい教科書や記事を読んで終わってしまっています。

もっとひどいときは、Twitterにシェアしただけで満足しちゃったり...!

せめて「わかったこと・わからなかったこと・思ったこと」は記録したいです。記録します。

 

具体的TODO

1.なりたい像を明確にする

→ これは会社が提供しているスキルマップがあるので、それができるようになることを目標にします。◯と×をつけて、現状を把握します。

 

2.優先順位をつける

→ ×を◯にすることを最優先課題にします。

 

3.何をすれば達成できるのか、勉強方法を考える

→ 具体的なタスクに落とし込みます。

 

4.振り返りをする

→ 「やったこと・わかったこと・わからなかったこと・思ったこと」のテンプレートでブログに記録していきます。

 

今日は1・2・3をやります。

 

 

Twitter課題修正プロジェクト - 認証・認可・OAuth2.0の復習をしよう

お久しぶりです。

つい先日、会社の研修が全て終わって業務が始まりました。

前回の記事で、JavaとRustの違いについて学ぶと豪語したものの...研修課題が難しすぎて、プラスαで学ぶ余裕がありませんでした。宣言を守れていなくてごめんなさい。

Rustに関しては技術書典3で記事を寄稿すると決めたので、そこに向けて勉強を再開するつもりです。

追い風と勝手に感じたのですが、ついにオライリーからRustの本がでるみたいです!

日本語訳出ないかな... 

Programming Rust: Fast, Safe Systems Development

Programming Rust: Fast, Safe Systems Development

 

 ---

余談はこれくらいにして、本記事の本題に移ります。

研修最後の課題がTwitter実装だったのですが、動けばいいだけのゴリゴリコーディングをしてしまいました。お師匠に教えていただいた内容をキャッチアップしきれていない状態なので、空き時間にリファクタリングを進めていきたいと思います。

このプロジェクトのゴールは個人用のAWSTwitter課題を公開し、社外の友達に見てもらうことです!

まずは認証部分のリファクタリングを行います。

 

使っているツール(前提条件)
  • Spring boot
  • Spring security
  • Java 8
  • Docker (mysql 5.6)
  • Flyway

 

どんな風に現状のコードが酷いのか?(自己分析)
  • そもそも認証、認可、OAuth2.0のことをよく理解していない
  • AbstractPreAuthenticatedProcessingFilterのことをよく理解しないまま実装に使った
  • 他のControllerが@RestControllerなのに、なぜか認証に関するControllerだけ@Controllerになっている
  • ユーザー名とパスワードの照合ができたときにアクセストークンを発行するのだが、jsonでクライアント側に返すのではなく、ヘッダーに入れて返している(お作法的にとっても気持ち悪いとのこと...)

 

どう直していくか
  1. 認証認可について理解を深める
  2. OAuth2.0について理解を深める
  3. AbstractPreAuthenticatedProcessingFilter使用例を見て、お作法を学ぶ
  4. 設計図を書く
  5. 見積もりをする
  6. 実装

 

認証認可について理解を深める

早速、認証認可についての理解を深めていきたいと思います。

「認証認可って何が違うんだ...一緒じゃないの?」

そんな迷える子羊だった私を救ってくれた記事がこちらでした。

dev.classmethod.jp

認証 ... 通信の相手が誰(何)であるかを確認すること

認可 ... とある特定の条件に対して、リソースアクセスの権限を与えること

普段よく使っているTwitterFacebookは、認証(ユーザー名とパスワード照合で本人であることを認める)と認可(本人として、投稿やいいね等ができるようになる)が同時に行われているものだったので、疑問が浮かんでしまったんですね。

 

OAuth2.0についての理解を深める

自作Twitterのログイン・ログアウト実装の際、

「今回は認可サーバーとリソースサーバーを分けないけど、OAuth2.0のResource Owner Password Credentials Flowの考え方で、APIへのアクセストークンを発行してみよう」

というお達しをもらったのですが、「ログインといえばCookieやセッション」しか知らなかったので、初めて教えて頂いた時に頭がパンクしたのを覚えています。

改めてOAuth2.0について理解を深めていきます!

まずは、OAuthが必要になった背景についてですが、wikipediaに端的にまとめられていました。

マッシュアップによるWebサービスの連携が増え、デジタルアイデンティティの共有が問題となってきた。OpenIDのような連合アイデンティティが解決策として登場したが、これはIDの持ち主による認証手段であって、それによってどのリソースにアクセスできるかという認可については扱っていない。あるWebサービスAにユーザーの個人情報があるとき、そのWebサービスAと別のWebサービスBが連携し、WebサービスAにある個人情報をWebサービスBが自由にアクセスできる状況は好ましくない。そのため、WebサービスAPIへのアクセスを認可する手段が必要とされていた。

続いて、Resource Owner Password Credentials Flowについてです。これについては、素晴らしいQiitaの記事で学ばさせて頂きました。

qiita.com

ここで疑問に思ったのが、「Resource Owner Password Credentials Flowだと、アプリ側がusernameやpasswordを持つことになってしまうけど、いいのかな?」ということです。このような疑問について、RFC 6749にこのようなことが書いてありました。

The resource owner password credentials grant type is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system or a highly privileged application.

It is also used to migrate existing clients using direct authentication schemes such as HTTP Basic or Digest authentication to OAuth by converting the stored credentials to an access token.

つまりこのフローは、クライアントが極めて信頼できる場合もしくはOAuthへ移行する場合に有効だということです。

今回のTwitter課題においては、「移行」というより「拡張性」という言葉が適切かもしれません。

「今はusernameもpasswordも自分たちのサーバーで管理しているけど、いつかは他のサービスに認証部分を任せるかもしれない。」

「他のサービスを使っているユーザー情報で認証するようになるかもしれない。」

そういった場合にこのフローをあらかじめ採用しておけば、一から新たに認証・認可に関する部分を作る必要がありません。

ソフトウェアの拡張性を高めるために、お師匠はResource Owner Password Credentials Flowを採択したのだと理解できました。...合ってるかな?笑

あとで確認します。

 

今日はここまで。

次回はAbstractPreAuthenticatedProcessingFilterの使用例を見て、お作法を学んでいきます。

 

 

JavaとRustの違いをひよっこエンジニアが比較していきます(予告)

お久しぶりです。
最後のブログ更新から時間が経ってしまいましたが...元気に毎日を過ごしています。
4月から新卒エンジニアとして某IT企業に入社、毎日もりもりコードを書いていますが...
アウトプットサボり過ぎじゃない?
ということで、ブログ更新をまた始めようと思い立ちました。
物書きの肩慣らしに、JavaとRustの比較をしていこうと思います。


なぜJavaとRustなのか

弊社の新卒エンジニアは、経験者と未経験者がちょうど半々くらいの割合です。
経験者の子たちはどんどん次の研修に進んでいるし、未経験者の子たちも地頭の良さでどんどん研修をこなしている...
一方私は研修課題を理解するのに精一杯で、未経験者を脱却できない己に苛立ちを覚えるようになってきました。
もっとJavaを使えるようになりたい。
具体的には、

  • 動けばいいや
  • IDE(IntelliJ IDEA)がサジェストしているから書き換えよう
  • 先輩が言っているからとりあえず直そう

という状況を打破したいです。
そのためには、文法やメソッドを覚えるだけでは足りない、Javaの設計思想や哲学を学ぶ必要があると思いました。
しかしながら、その必要性はわかるものの具体的にどう学べばいいのかさっぱりでした。

そんなときに出会ったのがRustというプログラミング言語です。
Rustの教材を読んでいて、

という疑問が浮かんできました。
違う言語に触れたことで「これはJavaの特徴なのか」という気づきを得たわけです。

私はまともに学び始めたものがJavaくらいなので他の言語はよく知らないのですが、Rustの教材には、

  • 初心者向け教材で隠蔽されがちな専門用語が登場する
  • Rustを開発している意義がはっきりと書かれている
  • 多言語との違いを明記してくれている

ので、個人的には設計思想や哲学を学ぶ上でも良い教材になりそうだなと感じました。


プログラマが知るべき97のこと

また、この本もJavaとRustを比較しようと思うきっかけになりました。

プログラマが知るべき97のこと

プログラマが知るべき97のこと

こちらの本でアンダース・ノラスさんが仰っていることにグッと心を惹かれました。

新しい言語を学び、その勘所をつかんだら、前から知っていた言語の使い方がそれまでと変わっていることに気づき、自分で驚くことがよくあります。

 

複数の言語について学ぶと、デザインパターンについての理解も深まります。

いろんな言語の勘所をつかんで、デザインパターンへの理解を深めていきたい!

そんなわけで、JavaとRustの違いをこれから記事にしていこうと思いました。
相当勉強しないと書けない記事なので、気合い入れて勉強していきます。

Cloud9でPDO接続をする方法

お久しぶりです。
気づいたら一ヶ月も空いてしまいました。
今日はCloud9でPDO接続する方法について書きたいと思います。

 

Cloud9とは

Cloud9とは、先日Amazonに買収された統合開発環境Webサービスのことです。Ruby On RailsやWord Pressなど、主要なフレームワークを簡単に利用することができます。Apache起動もワンクリックで行うことができ、サービス開発のトラインアンドエラーの強い味方です。

 

PDO接続とは

PDOとは、ブラウザとmysqlのデータベースを繋ぐPHPのクラスのことです。このクラス内のメソッドを用いることで、例えばメッセージフォームの内容をデータベース取り込むことができます。mysql上の特定のデータベースを指定し、編集を許可されたユーザーとしてログインするためのプログラムがPDO接続です。

 

問題提起

PDO接続には、サーバー名、ユーザー名、パスワード、データベース名などの情報が必要です。普段私はさくらVPSサーバー上でmysql+PHPwebサービスを開発しているのですが、cloud9上ではこれらの情報はどう書けばいいのかわからず非常に手こずりました。一応公式コミュニティページに方法が載っているのですが、mysqliクラスを用いているため、PDOクラスを用いたい私のニーズにはマッチしませんでした。

 

解決方法

こちらの記事を参考にしつつ、書いてみました。 qiita.com

index.php


define('DSN', 'mysql:host=127.0.0.1;port=3306;dbname=データベース名;charset=utf8;');
define('DB_USER', 'C9_USER');
define('DB_PASSWORD', '');

try{
$dbh = new PDO(DSN, getenv(DB_USER), DB_PASSWORD);
} catch (PDOException $e) {
print('Error:'.$e->getMessage());
die();
}

 

ポイント

・ホスト名とポート名が公式から指定されているものがある
・パスワードは無い(シングルクォーテーション2つ)
・DE_USER定数をgetenv関数に代入する

 

今日はこの辺で。これからもプログラミングの勉強頑張ります(*^^*)

 

PHPを用いて、MySQLのデータをGoogle Chart Toolsで描画してみました

お久しぶりです。気づいたら前回の投稿から3週間くらい経ってしまいました。

相変わらず、バイトでたくさんコーディングしています(`・ω・*)b

今日はタイトル通り、PHPMySQLからデータを引っ張ってきて、それをGoogle Chart Toolsと組み合わせてブラウザ上で描画した話です。検索しても古い記事しか出てこなくてかなり四苦八苦したので、今後の自分のためのメモとして、書くことにしました。

 

Google Chart Toolsとは - Charts  |  Google Developers

Googleが公開しているAPIで、これを用いればデータを簡単にブラウザ上で描画することが出来ます。JavaScriptで記述します。

 

目的

PHPを用いて、MySQLのデータをGoogle Chart Toolsで描画する

 

苦労したこと

・参考にしたこちらの記事

Google Chart Tools: How to create a line chart example with mySQL/PHP and JSON | Kometschuh - Blog

が、PHP 5.5.0 で非推奨になった拡張モジュールを用いており、PDO_MYSQLを用いた書き方に翻訳しなければいけなかったこと。

・データの格納を、Google Chart Toolsの書式にしなければならなかったこと。参考にしたこちらの記事

【PHP】MySQLに保存しているデータをJSONで吐き出す - Qiita

でデータを吐き出すと、

[{"date":"2016-04-01","A":"1890000","B":"784000","C":"0"},...

のように吐き出されてしまいます。Google Chart Toolsでは、データの書式が決まっていて、

['date', 'A', 'B', 'C'],

['2015-04-01', 1890000, 784000, 0],...

のようにしなければなりません。この書式変換も頭をかなり悩ませました。

 

実際のコード (※ PHP 5.3.3(cli), MySQL 5.1.73の環境です) 

functions.php

<?php

function connectDb( ) {
try {
array(PDO::MYSQL_ATTR_READ_DEFAULT_FILE => '/etc/my.cnf',
PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'php',
);
return new PDO(DSN, DB_USER, DB_PASSWORD);
} catch (PDOException $e) {
echo $e->getMessage();
exit;
}
}

 

config.php

<?php
define('DSN','mysql:host=localhost;dbname=dbname;charset=utf8');
define('DB_USER','user');
define('DB_PASSWORD','pass');
error_reporting(E_ALL & ~E_NOTICE);

 

index.php

<?php
require_once('config.php');
require_once('functions.php');

mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");
?>

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>棒グラフ</title>
<style>
h1 {
color: #696969;
}
</style>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
google.load('visualization', '1', {packages:['corechart']});
google.setOnLoadCallback(drawChart);

// データ読み込み

function drawChart() {
var data = google.visualization.arrayToDataTable([
['日付(月単位)', 'A', 'B', 'C'],
<?php
// DBに接続
$dbh = connectDb();
// SQL
$sql = 'SELECT * FROM sales';
// クエリ
$stmt = $dbh->query($sql);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 行の長さ取得
$length = $stmt->rowCount();
// カウント
$no = 0;
foreach ($result as $value) {
echo '[\''.$value["date"].'\', '.$value["infra"].', '.$value["software"].', '.$value["web"].']';
$no++;
if ($no !== $length) {
echo ",\n";
}
}
?>
]);
var options = {
width:900,
height:600,
chartArea: {
top:80,
left:200
},
fontName: 'メイリオ',
backgroundColor:'#EFF4F5',
isStacked: true,
colors: ['#2E8EF6', '#DA3A29', '#8EC43C'],
bar: {groupWidth: 20},
hAxis:{
title:'日付(月単位)',
titleTextStyle: {
fontName: 'メイリオ',
fontSize: 16,
italic: false,
bold: false,
color: '#696969'
},
textStyle: {
fontSize:12,
color: '#696969',
fontName: 'メイリオ'
},
slantedText: true
},
vAxis:{
title: '合計',
titleTextStyle: {
fontName: 'メイリオ',
fontSize: 16,
italic: false,
bold: false,
color: '#696969'
},
textStyle: {
fontSize:12,
color: '#696969',
fontName: 'メイリオ'
}
},
legend:{
position: 'top',
textStyle:{
fontName: 'メイリオ',
color: '#696969',
fontSize: 16
}
}
};
var chart = new google.visualization.ColumnChart(document.getElementById('graph1'));
chart.draw(data, options);
}
</script>
</head>
<body>
<h1>サンプル棒グラフ</h1>
<div id="graph1"></div>
</body>
</html>

 

上のコードで以下のようなグラフができました!

f:id:mi_progress_oOo:20160803085909p:plain

 

今回のコーディングポイントは、$stmt->rowCount();で行の長さを取得して、if文で

「最後の行以外は最後に,(カンマ)を付けてね」という文章を書いたところです!最後の行は,(カンマ)がいらない(つけるとエラーを吐きます)ので、それをforeach文でどのように表すのか、ああでもないこうでもないと四苦八苦したのが今回一番楽しいコーディングでした(*°ω°*)

これからもプログラミングの勉強頑張ります!!!