外部パッケージの導入

卒業制作として作成したWindowdsアプリをAndroidアプリ化しよう!

キャンペーンの元、学習を始めたDartフレームワークFlutterでしたが、 チュートリアルでの外部パッケージが思うように導入出来ず、早くも頭を悩ませているでびです。。

チュートリアル>外部パッケージ flutter.ctrnost.com


ランダムな文字列を取得するenglish_wordsパッケージを/pubspec.yamlに記述し (チュートリアル内では3.1.0バージョンが記述されていたので記事に従いました。) コンソール内でおなじみのコマンド

$ flutter packages get

を実行するもversion?のエラーが発生。
(エラー内容を控えておくのを忘れていました。。)

そこで、最新のバージョン4.0.0に変更し再実行するもNG。。

google先生に相談したところ、良記事を発見しました!(やった!!) flutternyumon.com

/pubspec.yamlに記述せずコンソールで以下を実行すると自動でpubspec.yaml > dependenciesへパッケージを導入してくれるようです。

$ flutter pub add パッケージ名

GROUPBYとHAVINGを使ったデータ抽出

最近OracleDBを触る機会が増えたので備忘録程度に。 早速行ってみよう!

問題文:
empテーブルからデータを検索しなさい。同じ職種が2人以上存在するデータを検索するものとし、下記の実行結果を参考にすること。

<実行結果_empテーブル>
| EMPNO     | ENAME            | JOB
----------  -----------------  ----------
| 001       | 鈴木 仁         | PL
| 003       | 高橋 ひとみ     | PL
| 004       | 大前 貢         | SE
| 005       | 真田 博之       | SE
| 007       | 神城 陣         | PG
| 008       | 結城 陣         | SE
| 009       | 博多 弁         | PG

GROUP BYとHAVING使うのは見えてたけど、サブクエリを定義する場所が分からず苦戦した。
ということで定番のテーブル作成から。実行結果を見たい方は、4番へ。

1.テーブル作成 empテーブル作成:

CREATE TABLE emp (
    empno varchar2(3) PRIMARY KEY,
    ename varchar2(20) NOT NULL,
    superior varchar2(20),
    hiredate date NOT NULL,
    sal number NOT NULL,
    job varchar2(30),
    deptno varchar2(2),
    FOREIGN KEY (deptno) REFERENCES dept (deptno) 
);


2.論理名付与

COMMENT ON COLUMN emp.empno IS '任意の論理名';

※empno=部署NO、empname=社員名、superior=上司、hiredate=入社日、sal=給与、job=職種、deptno=部署名


3.レコード挿入

INSERT INTO emp VALUES ('001', '鈴木 仁', NULL, '2000/01/01', 600000, 'PL', '01');
INSERT INTO emp VALUES ('002', '佐藤 幸助', '鈴木 仁', '2000/03/22', 350000, 'ブリッジSE', '01');
INSERT INTO emp VALUES ('003', '高橋 ひとみ', NULL, '2000/01/01', 500000, 'PL', '02');
INSERT INTO emp VALUES ('004', '大前 貢', '鈴木 仁', '2000/04/01', 320000, 'SE', '01');
INSERT INTO emp VALUES ('005', '真田 博之', '鈴木 仁', '2001/04/01', 300000, 'SE', '01');
INSERT INTO emp VALUES ('006', '大城 勉', '鈴木 仁', '2001/04/01', 300000, 'SE', '01');
INSERT INTO emp VALUES ('007', '神城 陣', '高橋 ひとみ', '2001/04/01', 280000, 'PG', '02');
INSERT INTO emp VALUES ('008', '結城 瞳', '高橋 ひとみ', '2002/04/01', 280000, 'PG', '02');
INSERT INTO emp VALUES ('009', '博多 弁', '高橋 ひとみ', '2003/04/01', 260000, 'PG', '02');
INSERT INTO emp VALUES ('010', '小山 浩', '高橋 ひとみ', '2006/04/01', 180000, 'デザイナー', '02');


4.クエリ定義

SELECT empno, ename, job
FROM emp
WHERE (job) IN
(
    SELECT job 
    FROM emp
    GROUP BY job
    HAVING count(*) > 1
);

キャラクターのジャンプ実装

以下の記事を参考にさせて頂きました。

アクションゲームのジャンプを滑らかにしよう with Siv3D その1 - 空飛ぶサトイモの書

キャラをジャンプさせよう | ゲームプログラミング入門~bituse~

ジャンプ処理 – プログラム学習

【Unity】マリオっぽいゲームを作るのに必要な5つのこと - おもちゃラボ

【Visual C#でゲームを作る】ブロック崩し編 その1 - おもちゃラボ

あらかじめpictureBoxとtimerを準備しておく。

・pictureBox⇒ツールボックスからpictureBoxを選択しForm内にドラッグ&ドロップ(nameは初期値を使用) ・timer⇒プロパティからEnabledを選択しTrueに変更。Intervalを25に設定。(nameは初期値を使用)

Form1のイベント内keyDownをダブルクリックしForm1_KeyDownメソッドを用意して下さい。

ボタン入力は各ボタンのフラグを用意しtrueの場合に動作する処理を記述します。

気分でVector型を使用しましたが、個別に変数を設定してもいけるはずです。 Vector型を使用するにはある手順が必要なので以下の記事を参考にして下さい。 プロジェクト名⇒参照の追加⇒WindowsBaseを追加

namespace ジャンプ {
    public partial class Form1 : Form {
        Boolean SpaceKeyCondition; // スペースキーのフラグ設定
        Vector speed;
        Vector kasokudo;
        Vector grav;
        
        public Form1() {
            InitializeComponent();
            this.speed = new Vector(0, 0);
            this.kasokudo = new Vector(0.5, -6.0);
            this.grav = new Vector(0, 0.3);
        }

        private void movePlayer() {
            if (SpaceKeyCondition) {
                pictureBox1.Top += (int)kasokudo.Y;
                kasokudo.Y += grav.Y;
                pictureBox1.Top += (int)kasokudo.Y;
                if (pictureBox1.Bottom > ClientSize.Height) { // pictureBox1のY座標がクライアントの高さに到達したら停止
                    pictureBox1.Top = ClientSize.Height - pictureBox1.Height;
                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e) {
            if (SpaceKeyCondition || LeftKeyCondition || RightKeyCondition) {
                movePlayer();
            }
        }

        private void Form1_KeyDown (object sender, KeyEventArgs e) { // キー入力
            if (e.KeyCode == System.Windows.Forms.Keys.Space) {
                SpaceKeyCondition = true;
            } else if (e.KeyCode == System.Windows.Forms.Keys.Left) {
                LeftKeyCondition = true;
            } else if (e.KeyCode == System.Windows.Forms.Keys.Right) {
                RightKeyCondition = true;              
            }
        }
    }
}

pictureBoxに画像を埋め込む

1.新規プロジェクトを立ち上げ、Form1.cs内にpictureBoxを配置して下さい。 f:id:antenna_ch1:20220207203951p:plain

2.pictureboxのサイズと設置場所はとりあえずどこでもいいです。 埋め込みたい画像をプロジェクト内に入れる作業を行います。 ソリューションエクスプローラー内のプロジェクト名を右クリック→追加→新しいフォルダーを選択しフォルダー名をResourcesにします。 f:id:antenna_ch1:20220207203946p:plain

3.画像を追加していきます。 ソリューション内のPropertiesをダブルクリックします。 f:id:antenna_ch1:20220207203940p:plain

4.このような画面に切り替わったら左のメニュー(画像ではアプリケーションとなっている部分)のリソース*をクリックします。 f:id:antenna_ch1:20220207203929p:plain

5.水色のメニュー「イメージ」横にある▼をクリックしイメージを選択してください。 f:id:antenna_ch1:20220207203859p:plain

6.文字列からイメージが表示される一覧画面へ切り替わります。 枠内に取り込みたい画像をドラッグ&ドロップで挿入します。

7.取り込み後の画面(?ブロックの画像を挿入しました) f:id:antenna_ch1:20220207203842p:plain

8.先ほど作成したResourcesフォルダー内に元画像データが保存されています。 f:id:antenna_ch1:20220207203725p:plain

namespace maptiptest {
    public partial class Form1 : Form {
        // 変数定義
        public Image img;
        private void Form1_Paint(object sencdr, PaintEventArgs e) {
            Graphics g = e.Graphics;
            // Properties内のResourcesからtestという画像を探す
            img = Properties.Resources.test;
            // 変数名, 設置する座標X, 設置する座標Y, 画像の幅Width, 画像の高さHeight);
            g.DrawImage(img, 10, 10, 48, 48);
        }
    }
}

9.記事の初めに設置したPictureBoxのプロパティ→イベントをもう一度開き、Paint項目に関数名(Form1_Pain)を記述してください。 f:id:antenna_ch1:20220207203824p:plain

10.以上のことをやり終え開始ボタンをクリックすると画像が表示されます。 f:id:antenna_ch1:20220207203810p:plain

職業訓練コード研究

 卒業した生徒さんが作ったアプリのソースコードを拝見する機会があったので読み込んでいました。  

授業ではインスタンスに引数を入れ別クラスのコンストラクタで値を初期化するという方法を学んだところで、

Hさんは、

①個別クラスのコンストラクタ内で値を設定

②基本クラスのコンストラクタ内でインスタンスを作成&初期化

するというものだったのでこんな書き方も出来るのかと勉強させて頂きました。

以下はソースコードの一部です。

// クラス定義
public class Hoge {
    // 変数の定義
    private string name;
    private int num;
    // コンストラクタの定義
    // 通常であればここで変数の初期化を行う
    public test() {
        A a = new A(); B b = new B();
    }
}
// クラス定義
public class A {
    public Value() {
        twitter = "hage";
        num = 1;
    }
}
// Bクラス定義
public class B {
    public Value() {
        twitter = "hige";
        num = 2;
    }
}

僕が考えていたクラス定義、インスタンス化、コンストラク

// クラスの定義
public class Hoge {
    // 変数の定義
    private string name;
    private int num;
    // コンストラクタ定義
    public Hoge(string name, int num) {
        // 変数nameと変数numを与えられた値で初期化
        this.name = name;
        this.num = num;
        // private name 変数へのアクセサ
        public name() {
            set {
                this.name = value;
            }
            get {
                return this.name;
            }
        }
        // private num 変数へのアクセサ
        public Num() {
            set {
                this.num = value;
            }
            get {
                return this.num;
            }
        }
    }
    public Main() {
        // インスタンス化と同時に個別の引数を格納する
        A a = new A("hage", 1);
        B b = new B("hige", 2);
    }
}

全くのド素人の意見ですが、人が書いたコードほど勉強になるものはないですね!

認証のsession分離

管理者と一般ユーザーログインページを実装し挙動を確認したが、sessionを更新する状態となっていため解消する必要があった。 ①userでログイン→session(user依存)保存

②adminでログイン→session(user依存)更新

タイトル通りsessionを分けて保存するように実装する。

①userでログインした場合はuserのセッションを保存

②adminでログインした場合はadminのセッションを保存

LoginController.php

 <?php

 namespace App\Http\Controllers\Auth;

 use App\Http\Controllers\Controller;
 use Illuminate\Foundation\Auth\AuthenticatesUsers;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Http\Request;

 class LoginController extends Controller {

 ^   use AuthenticatesUsers;

 ^   /**
 ^    * Where to redirect users after login.
 ^    *
 ^    * @var string
 ^    */
 ^   protected $redirectTo = '/home';

 ^   /**
 ^    * Create a new controller instance.
 ^    *
 ^    * @return void
 ^    */

 ^   // middlewareのコンストラクトを確認する
 ^   public function __construct() {
 ^   ^   $this->middleware('guest')->except('logout');
 ^   }

 ^   // 追加
 ^   protected function guard() {
 ^   ^   return Auth::guard('user');
 ^   }

 ^   public function logout(Request $request) {
 ^   ^   Auth::guard('user')->logout();
 ^   ^   return $this->loggedOut($request);
 ^   }

 ^   // ログアウトした時のリダイレクト先
 ^   public function loggedOut(Request $request) {
 ^   ^   return redirect(route('login'));
 ^   }
 }

LoginController.php

  <?php
  namespace App\Http\Controllers\Admin\Auth;
  
  //use App\Http\Controllers\Admin; // モデルを App\User から変更
  use App\Admin; // モデルを App\User から変更
  
  //use App\Http\Controllers\Admin\Auth;   // 追加
  use App\Http\Controllers\Controller;
  use Illuminate\Foundation\Auth\AuthenticatesUsers;
  use Illuminate\Http\Request;
  use Illuminate\Support\Facades\Auth;
  
  class LoginController extends Controller {
  
  ^   use AuthenticatesUsers;
  
  ^   /**
  ^    * Where to redirect users after login.
  ^    * ログイン後にユーザーをリダイレクトする場所。
  ^    *
  ^    * @var string
  ^    */
  ^   protected $redirectTo = 'admin/home';
  
  ^   /**
  ^    * Create a new controller instance.
  ^    * 新しいコントローラーインスタンスを作成します。
  ^    *
  ^    * @return void
  ^    */
  
  ^   // loginメソッドはないがmiddlewareのコンストラクトを確認する
  ^   // App\Http\Kernel.phpへ
  ^   public function __construct() {
  ^   ^   $this->middleware('guest:admin')->except('logout');
  ^   }
 
  ^   public function showLoginForm() {
  ^   ^   return view('admin.login');
  ^   }
  
  ^   protected function guard() {
  ^   ^   return Auth::guard('admin');
  ^   }
  
  ^   public function logout(Request $request) {
  ^   ^   Auth::guard('admin')->logout();
  ^   ^   return $this->loggedOut($request);
  ^   }
  
  ^   public function loggedOut(Request $request) {
  ^   ^   $request->session()->regenerate();
  ^   ^   return redirect('/admin/login');
  ^   }
  }

.envファイル

// コード規約に則り、"="の前後に空白を設けていた。
SESSION_COOKIE=auth
SESSION_COOKIE_ADMIN=auth-admin

Middleware

  <?php
  
  namespace App\Http\Middleware;
  
  use Closure;
  use Illuminate\Support\Facades\Auth;
  
  class RedirectIfAuthenticated
  {                                          
  ^   /**                                    
  ^    * Handle an incoming request.       
  ^    *
  ^    * @param  \Illuminate\Http\Request  $request
  ^    * @param  \Closure  $next           
  ^    * @param  string|null  $guard       
  ^    * @return mixed
  ^    */
  ^   public function handle($request, Closure $next, $guard = null)
  ^   {
  ^   ^   $redirectTo = "/home";
  
  ^   ^   // 管理者なら管理画面用ホームのパスを設定する
  ^   ^   if ($guard === "admin") {
  ^   ^   ^   $redirectTo = "/admin/home";
  ^   ^   }
  
  ^   ^   if (Auth::guard($guard)->check()) {
  ^   ^   ^   return redirect($redirectTo);
  ^   ^   }
  
  ^   ^   return $next($request);
  ^   }
  }

Exception

  <?php

  namespace App\Exceptions;

  use Exception;
  use Illuminate\Auth\AuthenticationException;
  use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
  
  class Handler extends ExceptionHandler
  {
        ...
  ^   public function unauthenticated($request, AuthenticationException $exception)
  ^   {
  ^   ^   if($request->expectsJson()) {
  ^   ^   ^   return response()->json(['message' => $exception->getMessage()], 401);
  ^   ^   }
  ^   ^   if (in_array('admin', $exception->guards())) {
  ^   ^   ^   return redirect()->guest(route('admin.login'));
  ^   ^   }
  ^   ^   return redirect()->guest(route('login'));
  ^   }
  };

cakePHP画像表示について

学習の進捗としてはPHPのベタ書きの学習を終え、CakePHP掲示板作成に着手しています。

学習した内容を少しづつでもアウトプットしていくために思いつきで始めました。

 

これから頑張る!

もしくは、

今プログラミング学習中だよ!

って方は是非もくもく会しましょう!

 

前置きはこれくらいにして、早速本題入ります。

 

※DBは作成済とします。

※ユーザー情報を保存するUsersテーブルと投稿内容を保存するPostsテーブルとユーザー画像を保存するためのUploadsテーブルを使用しています。

作成物としてはdb内に保存されているデータを取り出しViewで表示する。

表示するものは、

・ユーザー画像

・ユーザー名

・メールアドレス

・紹介文

上記の内容を表示するページを作っていきましょう。

View/Users/view.ctp

<
div class="user_view"> <h1>
<!-- dbからfile_nameを取得する --> <?php $path = $user['Upload']['file_name']; ?> <?php echo $this->Form->create('User'); ?>
<!-- file_nameの有無を判定する --> <?php if ($path) : ?>
<!-- 取得したfile_nameを表示 --> <?php echo $this->Html->image('/files/' . $path, array('alt' => 'user_image', 'width' => '100', 'height' => '100')); ?> <?php else : ?> <?php echo 'ユーザー画像:未登録'; ?> <?php endif; ?> <h1>ユーザー名:<?php echo $user['User']['username']; ?></h1> <h1>メールアドレス:<?php echo $user['User']['mailaddress']; ?></h1> <h1>一言コメント:
<?php $comment = $user['User']['comment']; ?> <?php if ($comment) : ?> <?php echo $comment; ?> <?php else : ?> <?php echo '未登録'; ?> <?php endif; ?> </h1> </div>

User hasOne Uploadでユーザー情報を取得

user_idが一致する画像を取得するため$user['Upload']['file_name'];でuploadsテーブルからfile_nameを取り出す。

条件分岐にかけ画像を表示する。

$this->Html->image('/files/' . $path, array('alt' => 'user_image', 'width' => '100', 'height' => '100'));

上記文章を指定することで、以下が出力されます。

<img src="/img/cake/files/file_name.jpg" alt="user_image" width="100" height="100" />

 optionでは他に設定可能なのでググると必要な情報が出てくると思います。