Qiita / Kobito 風MarkdownをPHPでうまくHTMLに出力するTips
Qiita の Markdown では、
```php:inc/hoge.php function hoge(){ echo "hoge"; } ```
と書くと、
inc/hoge.php ←ここは強調される function hoge(){ echo "hoge"; }
のように表示されます。
しかしPHPのMarkdownパーサーでこれを上手く表現できるものが見当たりませんでした。そこで PHP Markdown Extra で上記を表現するクイックハックをやってみたら上手くいったので、ここに載せておきます。
いろんなライブラリの中からこれを選択した理由は、DokuwikiのMarkdown Extraプラグイン
plugin:markdownextra [DokuWiki]
の内部で使っているものがこれだったからです。つまり、Qiita用に書いたMarkdownをそのままDokuwikiに貼り付けてきちんと表示されるようにする、というのが今回のミッションです。が、Dokuwikiを使っていなくてもPHPで上記を実現したいという人は、参考になると思いますので試してみて下さい。あくまでクイックハックですので元々実装されているコードブロックのclassやattrへの実装関係は完全に無視し、Qiita方言にのみ対応しています。
PHP Markdown Extra の改造
- まずは、PHP Markdown Extra からClassic version の PHP Markdown Extra 1.2.8 をダウンロードします。Dokuwiki の Markdown Extraプラグイン内で使用しているのは Classic version なのでLib版でなくこちらをダウンロードします。
- markdown.php の 2921行目からのdoFencedCodeBlocksと_doFencedCodeBlocks_callbackを以下のように書き換えます。
function doFencedCodeBlocks($text) { # # Adding the fenced code block syntax to regular Markdown: # # ~~~ # Code block # ~~~ # $less_than_tab = $this->tab_width; $text = preg_replace_callback('{ (?:\n|\A) # 1: Opening marker ( (?:~{3,}|`{3,}) # 3 or more tildes/backticks. ) [ ]* (?: \.?([-_a-zA-Z0-9]+) # 2: lang )? (:.*|) #3: filename [ ]* \n # Whitespace and newline following marker. # 4: Content ( (?> (?!\1 [ ]* \n) # Not a closing marker. .*\n+ )+ ) # Closing marker. \1 [ ]* (?= \n ) }xm', array(&$this, '_doFencedCodeBlocks_callback'), $text); return $text; } function _doFencedCodeBlocks_callback($matches) { $lang =& $matches[2]; $filename = substr($matches[3],1); if (trim($filename)!="") { $filename = "<div class=\"code-lang\">$filename</div>"; } $codeblock = $matches[4]; $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); $codeblock = preg_replace_callback('/^\n+/', array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock); $codeblock = "<div class=\"code-frame\" data-lang=\"$lang\">$filename<div class=\"highlight\"><pre>$codeblock</pre></div></div>"; return "\n\n".$this->hashBlock($codeblock)."\n\n"; }
- 変更点はこれだけです。
テスト
<?php require_once 'markdown.php'; $text = file_get_contents ('sample.md'); echo markdown($text)
Dokuwikiへの組み込み
Dokuwikiへの組み込みは以下の手順です。
- plugin:markdownextra [DokuWiki] をDokuwikiにインストールします。このプラグインは
で囲まれた範囲のみをMarkdownとしてパースするので、Dokuwikiルールでの記述と混在できて便利です。 - サーバ上のdokuwikiインストールディレクトリ配下の lib/plugins/markdownextra/markdown.php を上記のものに差し替えます。
以上です。プラグインマネージャで「更新」を行うと元の実装に戻ってしまうので注意して下さい。
その他のTIPS
Dokuwikiでmarkdownextraプラグインを使った箇所にスタイルを適用したい場合は、lib/plugins/markdownextra/syntax.phpの38行目あたり
function handle($match, $state, $pos, Doku_Handler $handler) { switch ($state) { case DOKU_LEXER_ENTER : return array($state, ''); case DOKU_LEXER_UNMATCHED : return array($state, '<div class="markdown">'.Markdown($match).'</div>'); //ここ case DOKU_LEXER_EXIT : return array($state, ''); } return array($state,''); }
にdivをつけてクラスを指定して下さい。あとはテーマのcssにdiv.markdownのスタイルを記述すればOKです。
ご質問、ご意見などあればお気軽にコメントどうぞ。
PlayFramework Scala版をいじってみた
前回Javaフレームワークの調査だったので、Scala版をスルーしたPlayFrameworkですが、今回はScalaやってみようという話が持ち上がったのでちょっといじってみることにしました。
まずはセットアップからですが、例のごとく箇条書きメインでさくっと。
環境構築
前提
PlayFrameworkのインストール
- 公式のtypesafe-activator-x.x.x-minimalをダウンロード。
- 解答し、中身のactivator.batを実行
- しばらくするとブラウザが http://127.0.0.1:8888/home で立ち上がる。
- この際、必要なものは自動的にダウンロードされ、サブディレクトリに配置される。
- 古いバージョンのActivatorが入っていても特に競合したりする様子はないが、コマンドウインドウに出てくるメッセージの中には古いリポジトリのパスも見えるので、他のバージョンが入っていることはわかっているっぽい。
- activator.batの場所に環境変数PATHを通す。もし古いバージョンがある場合には書き換える。
- テスト用のアプリケーション「testapp1」を作成
activator new testapp1 play-scala cd testapp1 activator run
- http://localhost:9000/ にアクセスするとYour new application is ready.というページが出る。
Eclipseの開発環境を作る
- project/plugins.sbtに以下を追加
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")
- Ctrl+Dで一旦activatorを抜けてから、testapp1フォルダ内で以下を実行
activator eclipse
- Eclipseを起動。
- 新規Workspaceを作成して開く。PreferenceでJDKのパス設定をしておく。
- EclipseにScala IDE プラグイン http://download.scala-ide.org/nightly-scala-ide-luna-211x をインストール。
- 再起動後、設定がどうこう言ってくるので、Yesをクリックして0msのところを5msなどに変えてOKする。
- 続いてscala-ide-play2 プラグイン https://github.com/scala-ide/scala-ide-play2/wiki をインストール。
- メニューの[File]-[Import]-[General]-[Existing Project into Workspace]でNext
- Select root Directoryでtestapp1フォルダを選択し、Finish
- プロジェクト内の*.scalaファイルをどれか適当に開き、Eclipseエディタ内で色付けなどが行われていることを確認。
- プロジェクト内のviews*.htmlファイルをどれか適当に開く。この時点では標準テキストエディタで開かれる。右クリックしOpen With → New Template Editorを選択するとHTML+Scalaのきちんと色分けされた表示になる。
これをデフォルトにするには、Opwn With → Other → New Template Editor を選択。Use this editor with ...にチェックを入れ、さらにUse it for all *.html...にもチェックを入れる。これではなぜか行かないのでPreference→Editorから行う。 - [Project]-[Property]-[Java Build Path]-[Libraries]でAdd Class Folderをクリック。プロジェクト内のtarget\scala-2.11\classesを選択してOK。
- コマンドウインドウ上で以下を実行
activator -jvm-debug 9999 run
- [Debug As]-[Debug Configuration]でRemote Java Applicationを指定し、Newで新規設定を追加。
- 以下の手順でデバッグテスト
- app/controllers/HomeController.scalaの以下の行にブレイクポイントをつける。
Ok(views.html.index("Your new application is ready."))
- http://localhost:9000/にアクセス。Debugパースペクティブに切り替わってブレイクポイントで止まればOK。
F8で最後まで実行するとブラウザにYour new application is ready.のページが表示される。
Eclipseでのデバッグのテスト
きちんとセットアップが完了していると、「Eclipse上のエディタでソースを編集→ブレイクポイントを設定→ブラウザでhttp://localhost:9000/をリロード」という手順でデバッグができる。これを確認。
- HomeController.scalaを以下のように編集
def index = Action { var str = "TEST" Ok(views.html.index(str)) }
- 上記ファイルを保存(重要)
- OKの行にブレイクポイントを設定
- http://localhost:9000/にアクセス。
- Eclipse上ではOK行のブレイクポイントで止まっている。Variablesビューでstrのところに"TEST"と表示されていることを確認。
- F8
- ブラウザ上にページが表示され"Your new application is ready."だった箇所が"TEST"になっていることを確認。
ここまでで気をつけること(ハマったこと)
- ネット上の情報では説明が省略されているが、コマンドウインドウではactivatorの中にいるのかそうじゃないのかによってコマンドの書き方が違う。たとえばEclipseプロジェクトにするには"activator eclipse"と打てと大体のブログなどには書かれているが、すでにactivatorの中にいる場合には単に"eclipse"と打つだけ。そうじゃないと意味不明なエラーがでてくる。
- バージョンに細かなところが違うっぽい。ここに書いた情報も現時点での最新バージョン同士の組み合わせなのでうまくいっているが、どこかのバージョンが変わるときっと全く同じ方法では動かなくなると思われる。特にaddSbtPluginの後ろの数字はPlayのバージョンではないので注意(勘違いしているサイトがいくつかあった)。sbteclipsenのサイト https://github.com/typesafehub/sbteclipse に行って、最新版の記述を確認すること。
- ネット上の情報を鵜呑みにしないこと。特にEclipseまわりの設定はいろんな人が書いているわりにはプロジェクトを開くところで終わっていて、デバッグできるようにするところまでは説明しておらず「実際にそれで開発していないんだろうな」と思えるものが非常に多い。
まだ調べていないこと
- Eclipse上で新しいファイルを追加した場合などにも自動的にそれらがEclipse上もPlay上も正常に実行(デバッグ)対象となり開発ができるのか。
- Eclipse外で追加したファイルについてはどうなのか。
- svnなどで他の開発者とソースを共有する場合に共有すべきファイルの範囲は?(Eclipseの設定ファイル類は共有してはならないはず)
- Eclipse上に大量のjarファイルが出てくる。これをまとめられないか?→おそらくユーザライブラリにすればいいんだが、users\xxx.ivy2内の多数のサブディレクトリにあるのでちまちま選ぶのが面倒。そもそも全部いるのか?あとそもそも.ivy2にダウンロードされてそれをリンクするというのは微妙な気がする。プロジェクトごとにバージョン違うかもしれないし。
- Firebirdで使えるか?→AnormがFirebirdに対応していないという情報があるが、最新のJayBirdでも同じかどうか確認。
MyBatisを軽く調べてみた
Spring を使う前提で、MyBatisを調べてみた。
そもそも僕はアンチO/Rマッパーなので、Hibernateなどはとても肌に合わない。MyBatisはR/Oマッパー(最近こういう呼び方は聞かなくなった)らしいので、期待している。
で、調べてみた。
という感じ。正直XMLというスッピンで読めるファイルにSQLを書くのが肌に合わない。まあ「Hibernate(JPA)よりはこっちでしょ」とは思うけれど、SQL定義をJavaで記述するSpring JDBCのRowMapperやResultSetExtractor方が自由度あるし、そもそも読みやすいんじゃないかと思った。まあSpring JDBCももうちょっと機能多くてもう少しラッピングされてるといいなと思うけど。
ということで今のところ Spring JDBCを使う方向で。
Spring Web Flowについて軽く調べてみた
前回Springについて調べた際に「よくわからない」まま放置していた Spring Web Flow について、やはりとても有用な匂いがするので調べてみた。
簡単にいうと、一連の画面遷移、たとえば入力画面→確認画面(あるいはエラー画面)→完了画面といった一連の画面遷移のセットに対して、その一連の処理用のスコープ(requestよりは長く、sessionよりは短い)を提供するフレームワーク、と考えればいいだろうか。
この間の画面遷移は一方だけではなく、エラー画面から入力画面に戻ったり確認画面から入力画面に戻ったり、あるいは途中で中止したりといういろんな経路がある。この間エンティティオブジェクトを保持し、終わったら破棄する、それを管理するものという風に理解した。
具体的には、Spring Web FlowがURLの後ろにキーを付加し、それが一連の処理の間ついてまわるという仕組み。
コントローラのみの実装なので、MVの部分は他に依存する。具体的にはSpring MVCやJSFなど。
ショッピングカードのようなものを作る場合に、とても理にかなったわかりやすい仕組みだと思う。だが、Spring MVCのコントローラが最初からこのようなスコープを持っていれば解決するんじゃないか、と使ったこともないのになんとなく思う。そして日本語情報の少なさにちょっと不安を覚える。
でもこれ、使ってみようかな。
Spring MVCから使うテンプレートエンジンをまとめてみた。
テンプレートエンジンについては未調査だったので調べてみた。Spring Bootが対応しているテンプレートエンジンは以下のとおり。
- FreeMarker
- Groovy
- Thymeleaf
- Velocity
- Mustache
- (JSP)
以下サンプルも交えるが調べただけで動かして試したわけじゃないのであくまで雰囲気メモで。
JSP
素のJSPを使うという選択肢は一番シンプルだが、Spring Bootとの相性が悪いような情報がいくつかあるので(なぜなのかは未調査)やめておこう。メリットなさそうだし。
FreeMarker
- 素のHTMLの地の部分に${hoge}と記述するタイプ。わかりやすい。
- が制御は<#hoge>タグというのを使うらしいのでここが素のHTMLじゃないので、ブラウザやIDE、エディタなどの挙動はどうなのか。
- Velocityとソックリ。
<!DOCTYPE html> <html> <head> <title>My Site</title> <link rel="stylesheet" href="/css/common.css"> </head> <body> <div class="innner"> <div class="outer"> <#if hoge??> <div>ハローワールド:${hoge}</div> </#if> </div> </div> </body> </html>
Groovy
- Spring Bootで使えるテンプレートエンジン、でググると良くGroovyが出てくるので何のことかと思ったら、Groovyの中にある「Markup Template Engine」を使用する、という意味だと思われる。ちなみにBootというより Spring MVC 自体がこれを使えるということらしい。
- groovyの関数でDOMを記述する仕組み。調べた感じこういう書き方?(動くかどうか知らない)
yieldUnescaped '<!DOCTYPE html>' html { head { title('My Site') link(rel: 'stylesheet', href: '/css/common.css') } body { div(class: 'outer') { div(class: 'inner') { if (hoge=hoge){ div("ハローワールド: $hoge") } } } } }
これが便利だと思う機会が今のところなさそう。
Thymeleaf
th:hogeというエレメントを使って素のHTMLで記述する仕様。FreeMarkerとは似て非なる。 FreeMarkerが制御を<#hoge>タグで構造化するのに比べると、th:hogeに全部やらせる仕様は構造化よりは関数型に近い考え方かな。 xmlnsを記述すればおそらく完全な正しいHTMLとして理解されるはずなので、IDEやブラウザ、エディタでの対応は他のテンプレートエンジンとくらべて一番確実なんじゃないだろうか。
ただ、th:エレメントってthタグとかぶってて検索精度が低いんじゃないだろうか。せめてty:とかだったら良かったのに。ちなみにdata-th-でも良いらしい。
<!DOCTYPE html> <html> <head> <title>My Site</title> <link rel="stylesheet" href="/css/common.css"> </head> <body> <div class="innner"> <div class="outer"> <div th:if="${hoge}" th:text="ハローワールド:${hoge}">ハローワールド:XXXX</div> </div> </div> </body> </html>
Velocity
- 有名なやつ。
- FreeMarkerとどう違うのかわからない。というかVelocityあるのになんでFreeMarkerあるのかわからない。使い込めばわかるのか。
<!DOCTYPE html> <html> <head> <title>My Site</title> <link rel="stylesheet" href="/css/common.css"> </head> <body> <div class="innner"> <div class="outer"> #if $hoge <div>ハローワールド:$hoge</div> #end </div> </div> </body> </html>
Mustache
- いろんな言語でサポートしているテンプレートエンジンらしい。
- すべてをテンプレート変数で制御する仕組み。ある意味凄い。
- {{#hoge}}...{{/hoge}}が汎用的につかえて、hogeが真偽値だったらif分、イテレーターだったらfor文として機能する。凄いんだけど、テンプレート見ただけだとどうなるのかわからない。
<!DOCTYPE html> <html> <head> <title>My Site</title> <link rel="stylesheet" href="/css/common.css"> </head> <body> <div class="innner"> <div class="outer"> {{#hoge1}} <div>ハローワールド:{{hoge2}}</div> {{/hoge1}} </div> </div> </body> </html>
まとめ
- 今のところ、情報の多いVelocityか、Spring Bootユーザの多そうなThymeleafか。
- テンプレートそのものをブラウザで表示した場合、FreemakerやVelocityはテンプレート変数が生で見えるが、Thymeleafはデフォルト値が見える。これは利点かもしれない。
Javaフレームワーク調査2015 - Spring編
結論からいうと、Play Frameworkがちょっと思ったより独自色+カジュアルな感じだったので、今回はSpring使う方向で考えています。 なのでフェアな比較記事路線ではなく、実際に使う上での懸念事項などをまとめたメモになります。
概要
- 当初はDIコンテナだったが、併用が想定されていたStrutsの出来が悪いため独自のMVCフレームワークも作られ、結果的にフルスタックになっている。ただしプロジェクトごとに使いたい機能を一部分だけ使うことができる。
メリット
- Spring Bootによって導入が簡単になった。
- 一部分だけを使えるので、一度学習するといろんなプロジェクトで利用/応用できる。
- ネット上の情報は非常に多い。Spring MVCも海外ではStruts以上に使われている。
デメリット
- Java EEなみに大きなプロジェクトで、全容を把握しづらい。
- 学習コストはそこそこ高い。
メリットでもありデメリットでもある点
- 一つの目的に対して幾つものソリューションがあるため取捨選択が大変だが、選択肢が多いことで守備範囲が広くつぶしがきく。
各論
DIコンテナ
- Spring Frameworkの要。僕は(多くの人がそうであるように)DIコンテナそのものの概念をSpringによって知ったくらいなので、DIコンテナとしての信頼性は高いと思っている。
- そもそもDIコンテナは「オブジェクト同士を疎結合にすること」と「オブジェクトの生成を一元管理すること」を目的にするためのものだと思うが、これを利用する副作用としてソースを一見して何が行われているのかわかりにくくなる。より正確に言うと「ビジネスロジックは見やすくなるが、ソースの実行順序は追いにくくなる」と思う。アノテーションと設定ファイル地獄になる。
- 思想的にはDDD(ドメイン駆動設計)が念頭にあるのではないかと思われるが、僕自身はDDDにはそれほど明るくない。
- バグを減らすためには実装時にはDIコンテナに任せるオブジェクトと、逐次newするオブジェクトを分けたほうがいいのではないかとなんとなく思う。ただしそのルールづくりが大変かもしれない。じゃないとその手法によってかえってバグが生まれるかもしれない。
Webフレームワーク
Spring MVC
- ベターStruts。SpringのDIを使って開発する場合、普通はこれを使うのだろう。
JSF
- Spring MVCを使わない場合の選択肢として有力なのは多分JSFだと思う。僕の理解では、Servlet寄りでMVCを提供するのがStrutsやSpring MVCだとすると、JSP寄り(HTML寄り)でMVCを提供するのがJSFという感じ。
- Java EEの一部だが単独で使用可能。
それ以外
Spring Web Flow
- ちょっと横道にそれて軽く調べた感じだと、Spring MVCであれJSFであれStrutsやTapestryであれ素のServlet/JSPであれ併用できる、画面遷移コントローラー(?)。
- 今のところ利用方法もメリットもさっぱりわからないが、ダークホースのにおいがする。
Spring Data REST
データアクセス
Spring Data JPA
- O/Rマッパー。
- JPAをSpring流儀で使いやすくしたもの。JPAの実装としてはHibernateを使用している。
- JPAの(Hibernateの)特徴をそのまま引き継ぐので、よくも悪くもJPAの(Hibernateの)評価と同じ。
- 僕はO/Rマッパー嫌いを自認している。僕にとって一般的な(JPA/Hibernate型の)O/Rマッパーを嫌う点として、以下のものがある。
- テーブル設計先行プロジェクト、あるいは既存プロジェクトへの適用が困難な点。
- 生成されるSQLのチューニングが難しい点。
- 複合主キーを使えない(使いにくい)点。
- 1対多の結合オブジェクトにおいて、1+多のクエリーが発行されてしまう点(俗にいうN+1問題)。
MyBatis
- MyBatis-Spring によってSpringとの連携が可能な、オルタナティブなO/Rマッパー。
- JPAとの最大の違いは、JPAのようにオブジェクトを定義することでSQLを自動生成するのではなく、逆にSQLを記述することでオブジェクトを生成する点。
- SQLはxmlに記述する。
- 僕は使ったことはないが、テーブル設計先行プロジェクトにおいての利用価値が高い点から、とても注目している。
- もうちょっと調査してみる。
Spring開発セット
Spring Roo
- Springでの開発効率を上げるためのコマンドラインツール。
- RADとあるが、DelphiやVBのようなものではない。
- Rooを使うとRooに依存したソースが生成される。その依存性は削除できるが削除するとRooからは利用できない。
- Rooが決め打ちで用意しているライブラリを必然的に使うことになり、選択の自由はあまりない(多分)。
Spring Boot
- Springの環境構築を容易にするためのSpringのスターターパック。
- 各モジュールはSpring Bootがあらかじめおすすめしているバージョンが組み合わせてあり基本的にはそれを使うことになる。
- 開発開始時点ではSpring Bootに用意されているものを利用しつつ、徐々にBoot外のものを利用していくこともできる。
- PHPやPerlにとってのXAMPPのようなものだと考えればいいか。
まとめ
- 現状では以下の構成で考えている。
- Apache HTTP Server
- Apache Tomcat
- Spring Framework (Spring Boot)
- Spring MVC
- MyBatis
Javaフレームワーク調査2015 - Play Framework編
前回の調査でなんとなくPlay FrameworkとSpringの2択かなと思ったので、この2つに絞ってさらなる調査をしてみました。 調査と言ってもググったり本読んだりするだけだし、すでに使ってる人にとっては既知の情報が多いと思います。
今回はPlay Framework編です。
概要
- Play Frameworkは現在のバージョン2.xはScalaで書かれていて、フレームワークの利用自体はScalaまたはJavaからできる。
- Play Framework自体がサーバ機能を持っており、Apache HTTP ServerもTomcatも必要ない。そもそもServletではない。
- 1.xはJavaで書かれていたが2.xでScalaで一から書きなおされている。
- フルスタックでほとんどのものが自前で用意されている。
メリット
- フルスタックなので、ライブラリごとの相性などをあまり気にする必要がなく、これさえ覚えていればだいたい完成まで漕ぎつけられる。
- 環境構築が楽で、すぐに開発が始められる。
- ネット上の情報量がなかなか多く、しかもその多くがかなりポジティブな評価。
デメリット
- 技術的難易度はそれほど高くないが、独自規格のためPlay Framework以外の技術との互換性が低く、結果的に学習コストがかかる。
- トレンドとしてはScala開発にあり、Javaでの利用はややマイナー。
- Apache httpd + Tomcat という世間一般的に当たり前のサーバを利用しないことによる、運用環境での不確定要素の多さ。
メリットでもありデメリットでもある点
- Typesafe Activator によるパッケージ管理。スムーズに動けば便利そうだけど、ちょっと使ってみた感じバギー。
- 色んな意味で今風でカジュアル。業務システムよりはWebサービス向きかも。
- ステートレス。つまり基本的にSessionを使わず状態をサーバ側で保持しない。全部をクライアント上に保存する。これにどういうメリットがあってどういう制約があるかはもいうちょっと考えないといけない。