Hiroto's diary

プログラミング関連とイベントの感想を書くかもしれない

JavaScriptの MediaDevices を使ってブラウザ上にカメラの映像をワイプ風に出す。

JavaScriptの試験的な機能の一つにMediaDevicesというのがあり、MediaDevicesを使うとカメラの映像なんかをJavaScriptで取得出来る。

developer.mozilla.org

MediaDevicesを使ってブラウザ上にカメラ映像をワイプ風に出して、テレビ番組みたいにしたら面白いかもと思い、実際にやってみた。

以下のコードをコンソールに貼り付けると左上にカメラ映像が出てくる。注意点としては実験的な機能なので対応していないブラウザがある事。FirefoxGoogle Chromeなどといった主要ブラウザの最新版なら大体動くはず。

圧縮版



YouTubeの動画の上にワイプを出してみる。動画はこれ。

www.youtube.com


FirefoxYouTubeを開き、ワイプを出してみた図。(左上が自分。)

YouTubeでワイプを出した図

…なるほど。

ちょっとだけ面白いかもしれないけど、動画を見てる時に自分が左上に映るのは普通に鬱陶しい。


フルスクリーンにしてもワイプは出てくるので、普通に使える。(何に?)

YouTubeでワイプを出した図



もうちょっとだけ考えてみたら、Electron製のアプリのコンソールにコードを打ち込めばワイプを出せるという気づきを得た。

自分が普段使ってるエディタの一つのVisual Studio CodeはElectron製なので、簡単にワイプを出せる。

Visual Studio Codeでワイプを出した図

CSSを少し変えてカメラの場所を動かし、gitのコンソールと撮影。バージョンアップ等でgit commitをする際に、コードやコミットメッセージと一緒に記念撮影が出来て便利かもしれない。

Visual Studio Codeでワイプを出した図

Laravelのpublicディレクトリを変更する。

タイトルの通り、Laravelのpublicディレクトリを変更する方法。hiroto-k.netサブドメイン統合に際してpublicディレクトリを動かしたのと、その後のテストでコケたのでその時のメモです。

先に書いておくと、この方法ではphp artisan serveコマンドは使えず、Homestead等で開発する必要が出てきますのでご了承ください。


まず最初に変更後のディレクトリ構成。サブドメイン毎でpublicディレクトリを分ける為、publicの中にapinetresourcesを掘り、既にあるindex.php等をコピーしました。。

f:id:Hiroto-K:20180607005533p:plain

次に各ディレクトリのindex.phppath.publicをバインドします。少し面倒ですが全てのindex.php$appの下に書き加えます。

<?php

// 省略

$app = require_once __DIR__.'/../../bootstrap/app.php';

$app->bind('path.public', function () {
    return realpath(__DIR__);
});

// 省略

書き換え後、Homesteadのsitestoで新しいpublicディレクトリの位置を指定してリロードすれば完了。HTTPからのアクセスでは、public_path等の返り値が設定したディレクトリで帰ってきます。

テスト時のディレクトリ設定

で、ここまでHTTPからのアクセスは何の問題も無いのですが、このまま何も設定せずにphpunitを走らせると、path.publicはデフォルトのpublicで帰ってきます。コントローラーなどでpublic_pathを使っていると確実にコケて非常に厄介です。

という訳でTestCaseからpublicディレクトリを変更出来るようにします。

TestCase.php$publicPathSuffixプロパティを生やすのと、createApplicationpath.publicをバインドする処理を追加。

<?php

use Illuminate\Contracts\Console\Kernel;
use Laravel\BrowserKitTesting\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{

    // 追加
    /**
     * Suffix of public path.
     *
     * @var string
     */
    protected $publicPathSuffix;

    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        // 追加
        if (isset($this->publicPathSuffix)) {
            $newPublicPath = public_path($this->publicPathSuffix);
            $app->bind('path.public', function () use ($newPublicPath) {
                return $newPublicPath;
            });
        }

        $app->make(Kernel::class)->bootstrap();

        return $app;
    }
}

コントローラー等のテストではpublicPathSuffixを設定。

AppsControllerTest.php

<?php

class AppsControllerTest extends TestCase
{
    protected $publicPathSuffix = 'net';
}

これでphpunitを走らせると、publicPathSuffixを設定したテストケースではpublicディレクトリの位置が変更されてテストが実行されます。

Laravelの .env の値はconfig()経由で使う。

結論から言うと…

  • env()は コントローラー, モデル, etc.. 内で直接使わない。
  • config/*.phpenv()の値を入れてconfig()から参照する。

<?php
// config/my-app.php

return [
    // configに.envの内容を入れる。
    'my-env' => env('MY_ENV'),
];
<?php
// コントローラー内など

// config() を使用。
$my_env = config('my-app.my-env');

// これはダメなパターン。
$my_env = env('MY_ENV');

何故 env() を使ってはいけないのか

本番環境でconfig:cacheコマンドを実行した際、.envファイルを読み込まないから。コレに尽きます。

.envファイルはIlluminate\Foundation\Bootstrap\LoadEnvironmentVariablesクラスのbootstrap()で読み込まれるのですが、読み込む前にconfigのキャッシュの有無を確認し、キャッシュがあった場合は.envファイルを読み込まない仕様になっています。

当該部分のLaravelのコードを引用。

<?php
// 省略

    public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) {
            return;
        }
        $this->checkForSpecificEnvironmentFile($app);
        try {
            (new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
        } catch (InvalidPathException $e) {
            //
        } catch (InvalidFileException $e) {
            die('The environment file is invalid: '.$e->getMessage());
        }
    }

// 省略

github.com

大体の場合の本番環境では、高速化の為に設定を一纏めにするconfig:cacheコマンドを実行すると思うのですが、前述の通りキャッシュがあると.envが読み込まれないので、env()を直接叩いてると開発時やテスト時には動くけど本番環境で死ぬ。といった事になります。(実際なった)

実際に試す

適当なコントローラーを用意してddを使って値をダンプするだけ。

<?php
class HogeController extends Controller
{
    public function getHoge()
    {
        dd(
            env('MY_ENV'),
            config('my-app.my-env')
        );
    }
}

まずはキャッシュ無しでアクセス。

"Foo"

"Foo"

テスト環境や開発環境と同じ様にキャッシュを作成していないのでどちらも同じ値が取得できます。

次にキャッシュさせてアクセス。artisanconfig:cacheを実行してbootstrap/cache/config.phpを作成します。

php artisan config:cache

で、先ほどと同じ様にアクセスしてみる。

null

"Foo"

.envファイルが読み出されていないのでenv()で取得した所で値が入ってる訳もなくnullを返します。


と言う訳で最初に書いた通り、env()は直接使わずにconfig().envの値を入れて使いましょう

© 2015-2018 Hiroto-K