tohokuaikiのチラシの裏

技術的ネタとか。

Confluenceのプラグイン開発を承ります。ご連絡はこちらのホームページからお願いいたします。

Confluenceのアドオンで別のアドオンのComponentを使う場合の注意

結論から言うと、その別のアドオンを事前にインストールしてないとインストールに失敗しますよということ。

お互いのComponentを循環参照するようなアドオンは作れないってことですね。

こんな簡単なことに気づかずにはまりました。

IDE上ではpom.xml

<dependency>
    <groupId>jp.example.confluence.plugins</groupId>
    <artifactId>foo</artifactId>
    <version>1.00.01</version>
    <scope>system</scope>
    <type>jar</type>
    <systemPath>${basedir}\foo-1.00.01.jar</systemPath>
</dependency>

って記述してたのでIDE自身はjarを見れていたので。

エラーの感じとしては

こんなのが出てた

Caused by: org.osgi.framework.BundleException: Unresolved constraint in bundle jp.example.confluence.plugins.bar [250]: Unable to resolve 250.0: missing requirement [250.0] osgi.wiring.package; (osgi.wiring.package=jp.example.confluence.plugins.foo.component)

まぁ、そりゃそうですよね。

Mediaqueriesの覚え方

いつもこんがらがるので・・・。

min-width

@media only screen and (min-width: 800px) {

「ブラウザが」800px幅が最低でも必要です => 800px以上のブラウザ幅で有効になります。

max-width

@media only screen and (max-width: 800px) {

「ブラウザが」800pxを越える時まで有効です。

minは「最低でも必要」、maxは「この大きさまで有効」

PHPで自分のクラスを見たSingletonの生成

今更って感じですが。

<?php
class Foo
{
    /**
     * @brief 
     * @param 
     * @retval
     */
    static function getSingleton()
    {
        static $cache ;
        
        if (is_null($cache)){
            $cache = new static();
        }
        return $cache;
    }
    
    
    /**
     * @brief 
     * @param 
     * @retval
     */
    function whoisme()
    {
        return get_class($this);
    }
}

class A extends Foo
{
}

class B extends Foo
{
}

$a = A::getSingleton();
var_dump($a->whoisme()); 
$b = B::getSingleton();
var_dump($b->whoisme()); 


$c = A::getSingleton();
var_dump($c->whoisme()); 
$d = A::getSingleton();
var_dump($d->whoisme()); 

で、$c/$dは$aと同じクラスA。$bはクラスB

ORMとしてActiveObjectsを使用する

Atlassianのデータを保存する場所といえば、BandanaでありContentPropertyManagerである。

tohokuaiki.hateblo.jp

が、JIRA4.4からConfluence4.3からは特に意識しなくてもActiveObjectsが使えるようになった。こちらの方が早くて軽くて大容量でそのプラグイン固有のデータを保存して利用することができるということだ。

以下の記事をベースに使い方を見てみる。
Getting Started with Active Objects - Atlassian Developers

使えるようにするには

まず、pom.xmlDependencyを記述

<dependency>
  <groupId>com.atlassian.activeobjects</groupId>
  <artifactId>activeobjects-plugin</artifactId>
  <version>${ao.version}</version>
  <scope>provided</scope>
</dependency>

で、${ao.version}というのはこのURLから自由に選んでくれっていうことらしい。チュートリアルでは1.2.3を使っている。Confluence用っぽい0.24-m5-confluenceっていうのがあってこれを使うといいのだろうか・・・・。 https://maven.atlassian.com/content/repositories/atlassian-public/com/atlassian/activeobjects/activeobjects-plugin/

あと、なぜかGoogle.collectionsも入れておいてって言われた。

<!-- Google Collections, useful utilities for manipulating collections -->
<dependency>
  <groupId>com.google.collections</groupId>
  <artifactId>google-collections</artifactId>
  <version>1.0</version>
  <scope>provided</scope>
</dependency>

ActiveObjectsとして使用されるClassを指定

atlasian-plugin.xml

<ao key="ao-module">
  <description>The module configuring the Active Objects service used by this plugin</description>
  <entity>com.atlassian.tutorial.ao.todo.Todo</entity>
</ao>

というように、使用するActive Objects Classを記述する。上記の場合、com.atlassian.tutorial.ao.todo.TodoクラスがActiveObjectとなって使用されるようになる。

前述のClassを実装

atlassian-plugin.xmlで記述した com.atlassian.tutorial.ao.todo.Todo をinterfaceで実装する。

setter/getterでエンティティを定義。この時「ID」は net.java.ao.Entityが使っているのでよっぽどでない限りOverwriteはしない。

package com.atlassian.tutorial.ao.todo;

import net.java.ao.Entity;

public interface Todo extends Entity
{
    String getDescription();

    void setDescription(String description);

    boolean isComplete();

    void setComplete(boolean complete);
}

ServletXWorkで使用する場合の準備

Servletの場合

public final class TodoServlet extends HttpServlet
{

    private final ActiveObjects ao;


    public TodoServlet(ActiveObjects ao)
    {
        this.ao = checkNotNull(ao);
    }

という感じでいつものようにConstructorでInjectionする。このaoを使って先ほどのEntity化されたObjectをCRUDする。

XWorkの場合

XWorkの場合はConstructorによるInjectionが無いのでsetter/getterを使うかと思いきや、このActiveObjectsにはそれが使えないっぽい。なので一旦ActiveObjectsを使うClassをComponentとして登録する。

一旦Componentを作成する。

まずatlassian-plugin.xmlでcomponentとして登録する

<component key="foo-service" name="Foo-Service" class="jp.example.com.FooServiceImpl" public="true">
    <interface>jp.example.com.FooService</interface>
</component>

jp.example.com.Fooのinterfaceを作成し、jp.example.com.FooImplを実装する。public=trueでないならinterfaceは不要なわけだと思うけど。

で、こいつのConstructorにてActiveObjectsをInjectionしてもらう。

import static com.google.common.base.Preconditions.checkNotNull;


public class FooServiceImpl implements FooService {

    private final ActiveObjects ao;

    public FooServiceImpl(ActiveObjects ao) {
    this.ao = checkNotNull(ao);
    }

で、XWorkの方でこのComponentを読み込む

XWorkでsetter/getterを定義してComponentを使えるようにする。

import static com.google.common.base.Preconditions.checkNotNull;

    private FooService fooService;
    
    public FooService getFooService() {
        return fooService;
    }
    public void setFooService(FooService fooService) {
        this.fooService = checkNotNull(fooService);
    }

Laravel5.4でAdminLTEを使う

AdminLTEという管理画面のテンプレートがある。これをLaravelで使いたい。

composerで簡単に使えるようにならないものか

と思って、packagistでLaravel adminlteで検索した。

ダウンロード数と☆数を見て・・・・と考えてるとインストーラ形式のこのパッケージがよさそうだった。

GitHub - acacha/adminlte-laravel: A Laravel 5 package that switchs default Laravel scaffolding/boilerplate to AdminLTE template and Pratt Landing Page with Bootstrap 3.0

acacha/adminlte-laravel-installerのインストー

既に、$HOME/.composer/vendor/bin とcomposerへのパスは通っているものとする。

$ composer global require "acacha/adminlte-laravel-installer=~3.0"
# 既存のLaravelプロジェクトDirectoryに移動
$ admilte-laravel install

これでインストールは完了。この際にacacha/admin-laravelから既存Laravelプロジェクトにファイルがコピーされるのだが、上書きされてしまうので注意が必要。特にconfig/app.phpとroutes/web.php routes/api.php config/database.phpは注意。

# ProviderとFacadeを登録
Adding Acacha\AdminLTETemplateLaravel\Providers\AdminLTETemplateServiceProvider::class to Laravel config app.php file
Adding Acacha\AdminLTETemplateLaravel\Facades\AdminLTE::class                          to Laravel config app.php file

# Controllerを登録(LaravelデフォルトのAuthControllerを変更)
Copied File [/vendor/acacha/admin-lte-template-laravel/src/stubs/HomeController.stub]           To [/app/Http/Controllers/HomeController.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/src/stubs/RegisterController.stub]       To [/app/Http/Controllers/Auth/RegisterController.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/src/stubs/LoginController.stub]          To [/app/Http/Controllers/Auth/LoginController.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/src/stubs/ForgotPasswordController.stub] To [/app/Http/Controllers/Auth/ForgotPasswordController.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/src/stubs/ResetPasswordController.stub]  To [/app/Http/Controllers/Auth/ResetPasswordController.php]

# 画像などのResourceをディレクトリごとコピー
Copied Directory [/vendor/acacha/admin-lte-template-laravel/public/img]          To [/public/img]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/public/css]          To [/public/css]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/public/js]           To [/public/js]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/public/plugins]      To [/public/plugins]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/public/fonts]        To [/public/fonts]
Copied File [/vendor/acacha/admin-lte-template-laravel/public/mix-manifest.json] To [/public/mix-manifest.json]

# エラービューなどをコピー
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/views/errors]                        To [/resources/views/errors]
Copied File [/vendor/acacha/admin-lte-template-laravel/resources/views/welcome.blade.php]                  To [/resources/views/welcome.blade.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/resources/views/layouts/partials/sidebar.blade.php] To [/resources/views/vendor/adminlte/layouts/partials/sidebar.blade.php]

# Assetの元ファイルをコピー
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/assets/css]  To [/resources/assets/css]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/assets/img]  To [/resources/assets/img]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/assets/less] To [/resources/assets/less]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/assets/sass] To [/resources/assets/sass]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/assets/js]   To [/resources/assets/js]

# などなど
Copied File [/vendor/acacha/admin-lte-template-laravel/webpack.mix.js] To [/webpack.mix.js]
Copied File [/vendor/acacha/admin-lte-template-laravel/package.json] To [/package.json]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/tests] To [/tests]
Copied File [/vendor/acacha/admin-lte-template-laravel/phpunit.xml] To [/phpunit.xml]
Copied Directory [/vendor/acacha/admin-lte-template-laravel/resources/lang] To [/resources/lang/vendor/adminlte_lang]
Copied File [/vendor/creativeorange/gravatar/config/gravatar.php] To [/config/gravatar.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/config/adminlte.php] To [/config/adminlte.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/routes/web.php] To [/routes/web.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/routes/api.php] To [/routes/api.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/.env.dusk.local] To [/.env.dusk.local]
Copied File [/vendor/acacha/admin-lte-template-laravel/.env.dusk.testing] To [/.env.dusk.testing]
Copied File [/vendor/acacha/admin-lte-template-laravel/src/stubs/AppServiceProvider.php.stub] To [/app/Providers/AppServiceProvider.php]
Copied File [/vendor/acacha/admin-lte-template-laravel/config/database.php] To [/config/database.php]

artisanコマンド

いくつかのartisanコマンドを提供してくれる。

Routesに追加

$ ./artisan make:route about

とすると、routes/web.phpに追加してくれる。ただし、#adminlte_routesというラインを見ているようなので、このラインを消してはいけない。

Viewを追加

./artisan make:view admin.about

とすると、resources/views/admin/about.blade.phpにテンプレートを追加してくれる。

管理画面Menuを追加する make:menuコマンド

これを行う前に、./artisan adminlte:menuでメニューを作成する。ただし、この機能はspatie/laravel-menuを使っていてこのlaravel-menuはPHP7以上でないとダメである。

adminlte:adminでダミーの管理画面ユーザーを作成

ダミーの管理ユーザを作成してくれる。

$ ./artisan adminlte:admin
File ...laravel_dir.../database/seeds/AdminUserSeeder.php created
User Admin(admin@example.com) with password 123456 created succesfully!

seedとしてAdminUserSeeder.phpが作られる。メールアドレスがadmin@example.comでパスワードが123456になる。.envに ADMIN_USERNAME, ADMIN_EMAIL, ADMIN_PWDを記述することで作成するSeedの値を操作できる。