tohokuaikiのチラシの裏

技術的ネタとか。

今更だけど、EthnaをPHP7にしてmysqliに対応した時のメモ

昔のコードのメンテナンスです(とか言ってみる

いい加減PHPも7になってEthnaはねーんじゃないの?って感じなのですが、これがまた意外と動くので使い続けたりしています。

ただ、preg_replaceのe修正子とmysql*系の関数が無くなったのでmysqli*に対応しないといけなくて、そのメモです。ちなみに、Ethna.phpをみると

/** バージョン定義 */
define('ETHNA_VERSION', '2.5.0-preview3');

とか書かれてたりします。

やらないといけないこと

  • preg_replaceのe修正子の削除
  • mysqliの適応
  • =&を=にする。(これは一括置換とか使って)

以下コードの羅列です。

etc/*****-ini.php

<?php
     'dsn' => 'mysql://user:pass@localhost/db_name',

 ↓

<?php
     'dsn' => 'mysqli://user:pass@localhost/db_name',

DB/Ethna_DB_PEAR.php

<?php

    function getInsertId()
    {
        if ($this->isValid() == false) {
            return null;
        } else if ($this->type == 'mysql') {
            return mysql_insert_id($this->db->connection);
        } else if ($this->type == 'sqlite') {


     function isValid()
     {
          if (is_null($this->db)
             || is_resource($this->db->connection) == false) {


    function quoteIdentifier($identifier)
    {
        if (is_array($identifier)) {
            foreach (array_keys($identifier) as $key) {
                $identifier[$key] = $this->quoteIdentifier($identifier[$key]);
            }
            return $identifier;
        }
            
        switch ($this->type) {
        case 'mysql':
            $ret = '`' . $identifier . '`';
            break;


    function &getMetaData($table)
    {
        $def =& $this->db->tableInfo($table);
            /** 中略 **/
            // flags
            $def[$k]['flags'] = explode(' ', $def[$k]['flags']);
            switch ($this->type) {
            case 'mysql':

 ↓

<?php

    function getInsertId()
    {
        if ($this->isValid() == false) {
            return null;
        } else if ($this->type == 'mysql') {
            return mysql_insert_id($this->db->connection);
        } else if ($this->type == 'mysqli') {
            return mysqli_insert_id($this->db->connection);
        } else if ($this->type == 'sqlite') {

     /* mysqli_connectはresourceではなく、Objectなので */
     function isValid()
     {
          if (is_null($this->db)
             || (is_object($this->db->connection) == false && is_resource($this->db->connection) == false)) {


    function quoteIdentifier($identifier)
    {
        if (is_array($identifier)) {
            foreach (array_keys($identifier) as $key) {
                $identifier[$key] = $this->quoteIdentifier($identifier[$key]);
            }
            return $identifier;
        }
            
        switch ($this->type) {
        case 'mysql':
        case 'mysqli':
            $ret = '`' . $identifier . '`';
            break;

    function &getMetaData($table)
    {
        $def =& $this->db->tableInfo($table);
            /** 中略 **/
            // flags
            $def[$k]['flags'] = explode(' ', $def[$k]['flags']);
            switch ($this->type) {
            case 'mysql':
            case 'mysqli':

preg_replaceのe修正子対応

Ethna_Controller.php

まとめて書く。

<?php
         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
         $action_name = substr(preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $target), 1);
         $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($action_name)) . '.' . $this->getExt('php');
         $postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($forward_name));
         $r = preg_replace('/_(.)/e', "'/' . strtoupper('\$1')", ucfirst($forward_name)) . '.' . $this->getExt('php');

 ↓

<?php
         $postfix = preg_replace_callback('/_(.)/', function($m){ return strtoupper($m[1]);}, ucfirst($action_name));
         $action_name = substr(preg_replace_callback('/([A-Z])/', function($m){ return '_' . strtolower($m[1]);}, $target), 1);
         $r = preg_replace_callback('/_(.)/', function($m){ return '/' . strtoupper($m[1]); }, ucfirst($action_name)) . '.' . $this->getExt('php');
         $postfix = preg_replace_callback('/_(.)/', function($m){ return strtoupper($m[1]); }, ucfirst($forward_name));
         $r = preg_replace_callback('/_(.)/', function($m){ return '/' . strtoupper($m[1]); }, ucfirst($forward_name)). '.' . $this->getExt('php');
<?php
        $name = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));

 ↓

<?php
        if (preg_match_all('/_(.)/', ucfirst($name), $m)){
            foreach ($m[1] as &$v) $v = strtoupper($v);
            $name = str_replace($m[0], $m[1], ucfirst($name));
        }

Plugin/Cachemanager/Ethna_Plugin_Cachemanager_Localfile.php

<?php
    function _escape($string)
    {
        return preg_replace('/([^0-9A-Za-z_])/e', "sprintf('%%%02X', ord('\$1'))", $string);
    }

 ↓

<?php
    function _escape($string)
    {
        return preg_replace_callback('/([^0-9A-Za-z_])/', function($m){
            return sprintf('%%%02X', ord($m[1]));
        }, $string);
    }

Ethna_MailSender.php

<?php
                 $part['name'] = preg_replace('/([^\x00-\x7f]+)/e',
                     "Ethna_Util::encode_MIME('$1')", $part['name']); // XXX: rfc2231
                 $part['filename'] = preg_replace('/([^\x00-\x7f]+)/e',
                     "Ethna_Util::encode_MIME('$1')", $part['filename']);
              /* ... */
              $header[$i][] = preg_replace('/([^\x00-\x7f]+)/e', "Ethna_Util::encode_MIME('$1')", $value);

 ↓

<?php
                 if (preg_match_all('/([^\x00-\x7f]+)/', $part['name'], $m)){
                     foreach ($m[1] as &$v) $v = Ethna_Util::encode_MIME($v);
                     $part['name'] = str_replace($m[0], $m[1], $part['name']);
                 }
                 if (preg_match_all('/([^\x00-\x7f]+)/', $part['filename'], $m)){
                     foreach ($m[1] as &$v) $v = Ethna_Util::encode_MIME($v);
                     $part['filename'] = str_replace($m[0], $m[1], $part['filename']);
                 }
              /* ... */
              $header[$i][] = preg_replace_callback('/([^\x00-\x7f]+)/',function($m){ return Ethna_Util::encode_MIME($m[1]); }, $value);

Ethna_AppObject.php

<?php
         $table = preg_replace('/^([A-Z])/e', "strtolower('\$1')", $table);
         $table = preg_replace('/([A-Z])/e', "'_' . strtolower('\$1')", $table);

 ↓

<?php
         if (preg_match_all('/^([A-Z])/', $table, $m)){
             foreach ($m[1] as &$v) $v = strtolower($v);
             $table = str_replace($m[0], $m[1], $table);
         }
         if (preg_match_all('/([A-Z])/', $table, $m)){
             foreach ($m[1] as &$v) $v = "_" . strtolower($v);
             $table = str_replace($m[0], $m[1], $table);
         }

=& newをつぶす

find lib app -name "*php"|xargs -I{} sed -i -e "s/ = &new/ = new/" {}
find lib app -name "*php"|xargs -I{} sed -i -e "s/ =& new/ = new/" {}

またdebianのvsftpdでハマったのでメモ

環境

uname -a
Linux www 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26) x86_64 GNU/Linux

いつものように、chrootしてバーチャルユーザーでのログイン。

症状1.

vsftpでつなごうとするとConnection Refusedされる。

ローカルからFTPコマンドでたたいても同じ。

$ ftp
ftp> open localhost
ftp: connect to address ::1: Connection refused
Trying 127.0.0.1...
ftp: connect: Connection refused

チェック項目

こんな感じで調べて何とかなった。

modprobeでモジュールチェック

# lsmod|grep ftp
nf_nat_ftp             16384  0
nf_nat                 28672  1 nf_nat_ftp
nf_conntrack_ftp       20480  1 nf_nat_ftp
nf_conntrack          114688  5 nf_conntrack_ftp,nf_conntrack_ipv4,nf_nat_ftp,xt_conntrack,nf_nat

これがなかったら以下を入れておく。

# modprobe nf_conntrack_ftp
# modprobe nf_nat_ftp

バーチャルユーザーのshell

とりあえずバーチャルユーザーの割り当てにはftp_userというユーザーを作ってたんだけど、これのshellが/usr/sbin/nologinだと動作しない。

vsftpd.conf

この2つは両立させられないらしいので、ipv6は使わないようにする。

listen=YES
listen_ipv6=NO

ホームディレクトリを555パーミッションに設定

こんな感じでバーチャルユーザーを設定していると、

# more /etc/vsftpd.d/vsftpd_user_conf/vftpuser
guest_username=vftpuser
local_root=/home/example

/home/exampleのパーミッションを555にしなければならない。

が、最近のVSFTPDだと

allow_writeable_chroot=YES

で行ける。

パッシブモードで引っかかる

このあたりでお勉強

FTPのアクティブモードとパッシブモード + vsftpdでの設定方法|A Day In The Boy's Life

centos - How to configure vsftpd to work with passive mode - Server Fault

どうもポートを開放しないとダメっぽい。あれー、今まで動いてたのになぁ・・・。

ということで、vsftpd.confに以下を記述。

pasv_enable=YES
pasv_min_port=61050
pasv_max_port=61100

で、iptablesをこんな感じで。192.168.xxx.xxxは自ホスト。

iptables -A INPUT -p tcp -s 0.0.0.0/0 -d 192.168.xxx.xxx --dport 61050:61100 -j ACCEPT
iptables -A OUTPUT -p tcp -s 192.168.xxx.xxx --sport 61050:61100 -d 0.0.0.0/0 -j ACCEPT

毎回何かしら引っかかるね。。。

PHPでeBayのAPIを使う

結論から言うと、APIのReferenceがあるけどそんなのは見なくてPHPSDKがあるからそれを使ったらすぐだった。

とにかく、SandboxとProductionの両方を行き来するのでどっちがどっちかわからなくなるし、いつの間にかアカウントできてたのでこの2つがリンクするというのはどういう風なんだろう?メールアドレスが同じものをSandboxとProductionの両方で使って登録すればいいのかしら?

わかんなくなったら、My eBayにそれぞれログインする。 * http://my.ebay.com:tilte=Production用 My eBay * Sandbox用 My eBay

eBay developerアカウントを作る

Sandbox用とproduction用の2つ作成。

どちらから作り始めてもいいのだけど、sandbox用は「testuser_」がPrefixになる。

正直、ごちゃごちゃとやってたら2個できたし、その2個がリンクしてるのはどうやって作るのかはわからない。

こっちに書いてあった、テスト用Sandboxユーザーの登録方法

eBay Features - Testing in the Sandbox

  • Set up an email account for each Sandbox test user. A unique email is required for each test user you create.
  • On the eBay Developers Program home page, either create a developer’s account by clicking the Register link or login by clicking the eBay Developer Login button.
  • Sign in as a developer, using your eBay Developers Program username and password.
  • Go to the eBay Sandbox User Registration Tool page.
  • Create your test user by filling in the Username and Password fields. You can leave the other fields as is. Click the Create User button.

アプリケーションを登録してキーを取得

Applicationの名前を決めて、そのキーを取得 f:id:tohokuaiki:20170905183629p:plain

これも、SandboxとProductionの両方。

色々と求められるかもしれないけど、とりあえず携帯電話のSMSがあればなんとか突破できる。

Authトークンを取得

「Auth'n'Aut」と「hOAuth (new security)」と2つあるけど2つとも取得しておく。

f:id:tohokuaiki:20170905183906p:plain

この時、これでもかというくらいにログインをさせられるけど我慢する。

Return URLを登録

Authした時に返却されるURLとかプライバシーポリシーなんかのURLを登録しておく。別にeBayが後でクロールしてチェックとかはしないので適当なURLを入れておけばOK。

f:id:tohokuaiki:20170905184326p:plain

これも、当然SandboxとProductionの両方。

PHP eBay API SDKを取得

素晴らしいサイトから取得する。 devbay.net

面倒なので、githubから直接。
GitHub - davidtsadler/ebay-sdk-examples: Several examples of using the eBay SDK for PHP

composer.jsonがあるので、例によってcomposer installする。

ebay-sdk-examples/configuration.php の設定

大体見ればわかると思う。

ruNameというのが引っかかったのだけど、これは、Return URL Nameということで、先ほど登録してReturn URLの名称なのである。自分の場合、上のキャプチャ画面だとTakashi_ITOH-TakashiI-Junoef-fbnbhijtpとかいうのがそれにあたる。

sellerアカウントを設定

とりあえずこれで使えることは使える。Select系のAPIはProductionを使用する。登録系のAPIはSandboxを使用する。

登録系のAPIを使うにはSellerアカウントにしないといけない。

そのためのセットアップがここにある。Getting started selling on eBay

すると、My eBayのアカウントページで「Seller Account」というのが出てくるらしい。

f:id:tohokuaiki:20170905190806p:plain

で、これを当然のようにSandboxとProductionの両方で行う。

が、SandboxのSellerアカウントが設定できない・・・

上述のは、Productionの設定しか書いてなかった。いや、むしろテストするだけならSandboxの方だけで構わないのに、Productionの方だけSellerアカウントができてしまった。

Sandboxは登録しなくてもSellerテストできるんじゃん?って思ってSDKのサンプル商品登録を試してみたら

Error: You need to create a seller's account.
Before you can list this item we need some additional information to create a seller's account.

って出た。デスヨネー。

仕方ないのでSandboxのMy eBayに行くと How to Sell Items on eBay などと書いてあり、

  • Sign up for PayPal (optional)
  • Fill out the Sell Your Item form

とある。optionalとあるPaypalの方は後回しにして、「go to the Sell Your Item form.」ってリンクをクリックするとリンク切れ。左のメニューにSeller Dashboardというのもあるのでそっちにヒントあるかな?と思ってクリックしたらリンク切れ。切れそう。

My eBay Viewsをシラミ潰す。

とにかくここに「Seller Account」というのが出ればいいのである。

f:id:tohokuaiki:20170905192629p:plain

しかし、PaypalにLinkさせればいいのかと思いきや、昔作って使えてたPaypalのアカウントがペンディングになっててダメだったり、新しくPaypalのSandboxユーザーで作ればいいんじゃないかと

f:id:tohokuaiki:20170906115646p:plain

ここのリンクから作ろうとしたら、PaypalのSandboxユーザー登録で電話番号がアメリカ形式じゃないとかZIPコードがお前の入力した住所と一致してないとかアメリカの電話番号・郵便番号の形式や実在するものを調べて入力したけどダメ。およそSandboxっぽくない。もちろん国をUSから変更することはできない。

困り果ててもう一度検索

もしかすると、作ったSandboxユーザーを「Sellerにする」という発想が間違っているのではないか?・・・すると、こんなページが見つかった。

eBay Features - Testing in the Sandbox

The process of registering a test user is different than that for registering a real user in the Production environment. After you register a Sandbox test user, you can use it to buy and sell test items in the eBay Sandbox.

買う用と売る用の2つのテストアカウントが必要ですよと。

なんだそんなの・・・売る用(Seller)アカウントが作れないから困ってるんだっていうの・・・と思いつつ、この画面のここからもう一つ作ってみる。

f:id:tohokuaiki:20170906120222p:plain

そして、新しいSandboxユーザーでログイン・・・・。

・・・なんかSellerアカウントになってるね。

f:id:tohokuaiki:20170906120524p:plain

で、Tokenを2つ発行して、configuration.phpに設定・・・

vagrant@debian:~/work/ebay/ebay-sdk-examples$ php trading/03-add-auction-item.php
The item was listed to the eBay Sandbox with the Item number 110222380931

おぉっ!!!できてる!!!ホンマ、なんつー、落とし穴やねん。。。

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で使いたい。

2019年追記:コッチの方が良さそう。

https://packagist.org/packages/jeroennoten/laravel-adminlte

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の値を操作できる。

Laravel5.4でAuthをつけたときにMySQLのmigrationでエラー

artisan migrateするとエラー。

specified key was too long max key length is 767 bytes

原因はだいたいここら辺で。

qiita.com

で、対策としてあげられている2つ

  • 使用するcharasetをutf8mb4から変更する は、app/Providers/AppServiceProvider.php
<?php
class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
        Schema::defaultStringLength(191);
    }

というようにbootでvarcharのデフォルト値を191にするということ。

  • カラムの最大値を変更し、767bytes以上の文字列が入らないようにする

絵文字いらないって言うのであれば、config/database.php

        'mysql' => [
            'driver' => 'mysql',
            ..(略)..
            'charset' => 'utf8mb4',
            'collation' => 'utf8_unicode_ci',

        'mysql' => [
            'driver' => 'mysql',
            ..(略)..
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',

にする。こっちの方が良い感じがする。

pom.xmlで依存性jarをローカルに置く方法

  1. pom.xmlに依存性のあるjarを設置する
  2. ${basedir}はpom.xmlのある位置なので、以下の記述をdependenciesに設置する
        <dependency>
            <groupId>jp.co.example.confluence.plugins</groupId>
            <artifactId>example</artifactId>
            <version>1.00.01</version>
            <scope>system</scope>
            <type>jar</type>
            <systemPath>${basedir}\example-1.00.01.jar</systemPath>
         </dependency>