LoginSignup
5
7

More than 5 years have passed since last update.

Sami で PHP プロジェクトの API ドキュメントを出力しよう

Last updated at Posted at 2017-01-12

Sami は Symfony の作者である Fabien Potencier さん作の API ドキュメント生成ツールです。
個人的には phpDocumentor2 よりもお手軽な気がしてます。
Symfony の API ドキュメント も、このツールで出力されています。

例として、 EC-CUBE の API ドキュメントを出力してみます。

下準備

アプリケーションを git clone しておきます。
タグごとや、ブランチごとドキュメントを出力することも可能です。
git clone したら、アプリケーションのディレクトリに移動します。

git clone git@github.com:EC-CUBE/ec-cube.git
cd ec-cube

設定ファイルの定義

sami_config.php を用意します。設定内容は以下の通りです。

  • Resource, cache, vendor の各ディレクトリを除いた *.php ファイルが出力対象
  • Git のタグごとにドキュメントを出力する
  • 3.0 ブランチ, master ブランチのドキュメントを出力する
  • api-theme 以下のディレクトリに、オーバーライドするテンプレートを格納
  • api-specifications 以下のディレクトリにドキュメントを出力する
  • cache 以下のディレクトリにドキュメントのキャッシュファイルを出力する
sami_config.php
<?php

use Sami\Sami;
use Sami\Version\GitVersionCollection;
use Sami\RemoteRepository\GitHubRemoteRepository;
use Symfony\Component\Finder\Finder;

// Symfony\Finder で探索したファイルが出力対象となる
$iterator = Finder::create()
    ->files()
    ->name('*.php')
    ->exclude('Resource')
    ->exclude('cache')
    ->exclude('vendor')
    ->in($dir = __DIR__);

// ブランチや、タグごとにドキュメントを出力する場合の設定
$versions = GitVersionCollection::create($dir)
    ->addFromTags('3.0.*')
    ->add('3.0', '3.0 branch')
    ->add('master', 'master branch')
;

// 出力ディレクトリや、テンプレートの設定
return new Sami($iterator, array(
    'theme' => 'eccube',
    'title' => 'EC-CUBE3 API Specifications',
    'versions' => $versions,
    'build_dir' => __DIR__.'/api-specifications/%version%',
    'cache_dir' => __DIR__.'/cache/%version%',
    'template_dirs' => array(__DIR__.'/api-theme')
));

必要に応じて、オーバーライドするテーマを用意します

template_dirs のディレクトリに manifest.yml を置くことで、独自のテーマを作成できます。

api-theme/manifest.yml
name:   eccube
parent: default

template_dirs は config.php で指定できます。

config.php
$templates = $sami['template_dirs'];

$templates[] = __DIR__ . '/../themes/';


$sami['template_dirs'] = $templates
api-theme/layout/layout.twig
{% extends "layout/base.twig" %}

{% block content %}
    <div id="content">
        <div id="left-column">
            {{ block('control_panel') }}
            {{ block('leftnav') }}
        </div>
        <div id="right-column">
            {{ block('menu') }}
            {% block below_menu '' %}
                <div id="page-content">
                    {% block page_content '' %}
                </div>
                {{ block('footer') }}
        </div>
    </div>
{% endblock %}

{% block menu %}
    <nav id="site-nav" class="navbar navbar-default" role="navigation">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-elements">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="{{ path('index.html') }}">{{ project.config('title') }}</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-elements">
                <ul class="nav navbar-nav">
                    <li><a href="{{ path('classes.html') }}">Classes</a></li>
                    {% if has_namespaces %}
                        <li><a href="{{ path('namespaces.html') }}">Namespaces</a></li>
                    {% endif %}
                    <li><a href="{{ path('interfaces.html') }}">Interfaces</a></li>
                    <li><a href="{{ path('traits.html') }}">Traits</a></li>
                    <li><a href="{{ path('doc-index.html') }}">Index</a></li>
                    <li><a href="{{ path('search.html') }}">Search</a></li>
                </ul>
            </div>
        </div>
    </nav>
{% endblock %}

{% block leftnav %}
    <div id="api-tree"></div>
{% endblock %}

{% block control_panel %}
    <div id="control-panel">
        {% if project.versions|length > 1 %}
            <form action="#" method="GET">
                <select id="version-switcher" name="version">
                    {% for version in project.versions %}
                        <option value="{{ path('../' ~ version ~ '/index.html') }}" data-version="{{ version }}">{{ version.longname }}</option>
                    {% endfor %}
                </select>
            </form>
        {% endif %}
        <script>
            $('option[data-version="'+window.projectVersion+'"]').prop('selected', true);
        </script>
        <form id="search-form" action="{{ path('search.html') }}" method="GET">
            <span class="glyphicon glyphicon-search"></span>
            <input name="search"
                   class="typeahead form-control"
                   type="search"
                   placeholder="Search">
        </form>
    </div>
{% endblock %}

{% block footer %}
    <div id="footer">
        Generated by <a href="http://sami.sensiolabs.org/">Sami, the API Documentation Generator</a>.
        <address>(c) EC-CUBE</address>
    </div>
{% endblock %}

ドキュメントの出力

以下のコマンドを実行することで、 API定義を出力可能です。

curl -O http://get.sensiolabs.org/sami.phar
php sami.phar parse sami_config.php
php sami.phar render sami_config.php

こんな感じ の API ドキュメントが出力できます!

2回目からは、前回の内容がキャッシュされているので、 update オプションで更新できます。

php sami.phar update sami_config.php
5
7
2

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
5
7