PHP
mariadb
cakephp3

CakePHP3でプロジェクト作成

Windows系のプロジェクトをたくさん作りましたが、
WEB系はプロジェクトマネージャーとHTML作成の経験しかないでした。

今回はcakephp3で、一からプロジェクトを作って見ます。

1、ローカル環境構築
2、DBテーブル
3、Bakeしてみよう
4、汎用SQLの利用方法
5、Global変数
6、Global関数
7、ControllerからViewへ複数の変数を渡す
8、エクセルファイル読み込む
9、エクセルファイル書きだす
10、サーバー環境構築
11、Templateビューの編集

1、ローカル環境構築
  参照サイト:
  http://tech.pjin.jp/blog/2016/06/30/howto-baking-bulletinboard/

  XAMPPのインストールサイト:
  https://www.apachefriends.org/jp/index.html

  CakePHPのダウンロードサイト
  http://www.phpbook.jp/cakephp/install/index1.html

2、テーブル
 今回のプロジェクトは13のテーブルがあります。
10000001.jpg

マスターデータ設定は、CSVファイルをインポートする。

3、BAKEしてみよう

htdocs/gramanagerにて、下記のコマンドを実行した。

php bin/cake.php bake all gramanager

NetBeansエディターで開けてみたら、この感じです。
※NetBeansでctpファイルが認識できなかった問題は、下記サイトを参照して解決しました。
http://gomocool.net/gomokulog/?p=117

image.png

4、汎用SQLの利用方法
コントローラーに下記参照を追加したら、汎用SQLでデータを取れます。
登録・更新・削除もできます。

use Cake\ORM\TableRegistry;
use Cake\Datasource\ConnectionManager;

//ログイン者の漢字名を取得

 public function cal_user_janame($manager_id) {

       $janame='';

        $connection = ConnectionManager::get('default');

        $statement = "SELECT * FROM managers WHERE managers.id = '$manager_id'";

        $stmt = $connection->execute( $statement)->fetchAll('assoc');

        foreach ($stmt as $row) {

            $janame = $row['name'] ;

            $GLOBALS["current_directorA"]= $row['directora_id'];
            $GLOBALS["current_directorB"]= $row['directorb_id'];
            $GLOBALS["current_directorC"]= $row['directorc_id'];

         }

      return   $janame;
 }

5、Global変数

   App\Controllerに、このように定義できます。

   $GLOBALS['current_user_id']=$this->Auth->user('name');

参照:PHP $GLOBALS(グローバル変数)のすべて!
http://wepicks.net/phpref-globals/

6、Global関数

//ログイン者の漢字名を取得

 public function cal_user_janame($manager_id) {

7、ControllerからViewへ複数の変数を渡す
 自動作成されたコードは、1テーブルの全データをcontrollerから、ctpへ渡す。

 複数のデータを渡すのは、Controllerに定義できます。

public function index()
{
$this->paginate = [
'limit' => 50,
'contain' => ['Managers']
];

    $homes = $this->paginate($this->Homes);

    $this->set(compact('homes'));
    $this->set('_serialize', ['homes']);

    ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑  条件なしなら、テーブルのデータを丸ごと渡す。

    $manager_id=$GLOBALS["current_manager_id"];
    $year_number=$GLOBALS["current_year"];
    $sec=$GLOBALS["current_sec"];  

    $this->paginate = [
                    'limit' => 50,
                    'contain' => ['Managers'] 
                   ,'conditions' =>array(
                       'and' => array(
                            'Homes.year_number' =>  $GLOBALS["current_year"],
                            'Homes.sec' =>  $GLOBALS["current_sec"],
                            'Homes.manager_id' => $GLOBALS["current_manager_id"]
                       ))
                    ,'group' => 'Homes.manager_id'
                    ,'order' => array('Homes.manager_id') 
                    ];    

    $homes_self = $this->paginate($this->Homes);
    $this->set(compact('homes_self'));

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑  一部のデータ

    $this->paginate = [
                    'limit' => 50,
                    'contain' => ['Managers'] 
                   ,'conditions' =>array(
                       'and' => array(
                            'Homes.year_number' =>  $GLOBALS["current_year"],
                            'Homes.sec' =>  $GLOBALS["current_sec"],
                            'Homes.dira_shainid' => $GLOBALS["current_user_id"]
                       ))
                    ,'group' => 'Homes.manager_id'
                    ,'order' => array('Homes.manager_id') 
                    ];    

    $homes_A = $this->paginate($this->Homes);
    $this->set(compact('homes_A'));

    ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑  一部のデータ

}

ビュー側:

タイトル

    <thead valign="top">
        <tr>
            <th scope="col" class="actions"><?= __('AA') ?></th>
            <th scope="col" class="actions"><?= __('AAAAA') ?></th>
            <th scope="col" class="actions"><?= __('AAAA') ?></th>
            <th scope="col" class="actions"><?= __('AAA') ?></th>
            <th scope="col" class="actions"><?= __('A') ?></th>
            <th scope="col" class="actions"><?= __('A') ?></th>
            <th scope="col" class="actions"><?= __('A') ?></th>
            <th scope="col" class="actions"><?= __('A') ?></th>
            <th scope="col" class="actions"><?= __('Action') ?></th>
        </tr>
    </thead>
</table>


条件A:
<?php if ($GLOBALS['current_rank_id'] < 7 and $GLOBALS['current_rank_id'] >2) : ?>

      <h5>本人</h5> 
       <table cellpadding="0" cellspacing="0">

             <?php foreach ($homes_self as $home_self): ?>    
              <tr>  
                <td><?= $home_self->has('manager') ? $this->Html->link($home_self->manager->name, ['controller' =>              'Targets', 'action' => 'index', $home_self->manager->id]) : '' ?></td>
                <td><?= h($home_self->target_put) ?></td>
                <td><?= h($home_self->dir_permission) ?></td>         
                <td><?= h($home_self->self_put) ?></td>                
                <td><?= h($home_self->director_aput) ?></td>
                <td><?= h($home_self->director_bput) ?></td>
                <td><?= h($home_self->director_cput) ?></td>
                <td><?= h($home_self->director_over) ?></td>

                <td class="actions">
                    <?= $this->Html->link(__('編集'), ['action' => 'edit', $home_self->id]) ?>
                </td>

             </tr>
             <?php endforeach; ?>
        </table>   

<?php endif; ?>

条件B

<?php
if ($GLOBALS['current_rank_id'] < 5 or $GLOBALS['current_rank_id'] ==7) {
echo "

一次
" ;
}
?>
    <table cellpadding="0" cellspacing="0">

     <?php foreach ($homes_A as $home_A): ?>
        <tr>

        <td><?= $home_A->has('manager') ? $this->Html->link($home_A->manager->name, ['controller' => 'Targets',          'action' => 'index', $home_A->manager->id]) : '' ?></td>
        <td><?= h($home_A->target_put) ?></td>
        <td><?= h($home_A->dir_permission) ?></td>      
        <td><?= h($home_A->self_put) ?></td>      
        <td><?= h($home_A->director_aput) ?></td>
        <td><?= h($home_A->director_bput) ?></td>
        <td><?= h($home_A->director_cput) ?></td>
        <td><?= h($home_A->director_over) ?></td>

        <td class="actions">
            <?= $this->Html->link(__('編集'), ['action' => 'edit', $home_A->id]) ?>
        </td>

        </tr>
      <?php endforeach; ?>
      </table>   

8、エクセルファイル読み込む
エクセルファイルのデータををDBへ読み込む出来ます。

・PHPExcelのインストール

https://github.com/PHPOffice/PHPExcel

上記URLにアクセスし、Clone or downloadボタンをクリックします。
さらに「Download Zip」をクリックすると、zipファイルがダウンロードされます。
(2017/8/24時点 のファイル名は PHPExcel-1.8.zip)

ダウンロードしたzipファイルを解凍し、
解凍フォルダ内のClassesフォルダの中身を全て、使用したいphpファイルが読み込める場所にコピーします。
自分はすべてtmpに保存しました。
Documentationフォルダ、Examplesフォルダ等は不要です。

・モデルなしのUploadsControllerとupload formを利用します。  

UploadsControllerのコード:

<?php
namespace App\Controller;

use App\Form\UploadForm;
use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;

require_once(realpath(TMP).DS."classes".DS."PHPExcel.php");
require_once(realpath(TMP).DS."classes".DS."PHPExcel".DS."IOFactory.php");
use PHPExcel_IOFactory;

class UploadsController extends AppController
{
public function index()
{
$upload = new UploadForm();

    if ($this->request->is('post')) {

        if ($upload->readFromExcel($this->request->data['file']['tmp_name'])) {
            $this->Flash->success('アップロードが成功しました');

            echo "<br/>";
            echo $this->request->data('file.name')." を正常インポートしました。";
            echo "<br/>";

        } else {
            $this->Flash->error('バリデーションに引っかかりました。');
            echo $this->request->data('file.name')."をインポートできませんでした。";
        }
    }

    $this->set('upload', $upload);
}  

}

UploadFormのコード:

<?php

namespace App\Form;

use app\Controller\AppController;
use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Validation\Validator;

use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;

require_once(realpath(TMP).DS."classes".DS."PHPExcel.php");
require_once(realpath(TMP).DS."classes".DS."PHPExcel".DS."IOFactory.php");

use PHPExcel_IOFactory;

class UploadForm extends Form{

// ファイル名渡したら配列返すラッパー関数
public function readFromExcel($inputFile)

{

 $readFile = $inputFile;

// ファイルの存在チェック
if (!file_exists($readFile)) {
    exit($readFile. "が見つかりません。" );
}

// xlsxをPHPExcelに 
$objPExcel = PHPExcel_IOFactory::load($readFile);
$sheet = $objPExcel->getActiveSheet();

$shainid = $sheet->getCell( 'A3' )->getValue();

 $upController = new AppController;

 $manager_id= $upController->get_manager_id_from_shainid($shainid);

 $directora_id= $upController->get_directorid($shainid,"a") ;


 $directora_shainid=$upController->get_shainid_from_directorid($directora_id,"a");



$year_number=$GLOBALS["current_year"];   //計算
$sec=$GLOBALS["current_sec"];         //計算

//既存を削除
$connection = ConnectionManager::get('default');
$connection->delete('targets', ['year_number' => $year_number,'sec' => $sec, 'manager_id' => $manager_id]);

 $i=0;
    $firstLine=27;
    $cellLine = $firstLine ;

        for($i = 1; $i < 6; $i++){

            $cellB="B" .strval($cellLine);
            $cellO="O" .strval($cellLine);
            $cellAB="AB" .strval($cellLine);

            ・・・

            $mokuhyou = $sheet->getCell($cellB )->getValue();
            $plan = $sheet->getCell($cellO )->getValue();
            $weight = $sheet->getCell($cellAB )->getValue();

            ・・・
            date_default_timezone_set('Japan');
            $created = date('Y/m/d H:i:s');

           // $connection = ConnectionManager::get('default');

            if ( strlen($mokuhyou) > 0) {

                $connection->insert('targets', [
                    'year_number' => $year_number,
                    'sec' => $sec,
                    'subid' => $i,
                    'manager_id' => $manager_id,
                    'target' => $mokuhyou,
                    'plan' => $plan,
                    'weight' => $weight,
                    'status' => '編集中',
                    'self_coment' => $self_coment,
                    'self_degree' =>$self_degree,
                    'director_txt' => $director_txt,
                    'directora_id' => $directora_shainid,
                    'directorb_id' => $directorb_shainid,
                    'directorc_id' => $directorc_shainid,
                    'degree_a' =>  $degree_a,
                    'degree_b' =>  $degree_b,
                    'degree_c' =>  $degree_c,
                    'created' =>  $created,
                    'created_user' => $GLOBALS["current_user_janame"]]);
             }


            $cellLine =  $cellLine + 4;

        }
         return true;
}

}

・Upload.ctp: アップロードファイルを選択する。



  • = $this->Html->link(__('Home'), ['controller' =>'Homes', 'action' => 'index']) ?>


  • = $this->Form->create($upload, ['type' => 'file']) ?>

    = $this->Form->file('file') ?>

    = $this->Form->button('アップロード', ['type' => 'submit','id' => 'register']) ?>
    = $this->Form->end() ?>

9、エクセルファイル書きだす
 参照:
 http://qiita.com/suin/items/7a8d0979b7675d6fd05b

 書き出すはアップロードよりシンプルです。
 固定のフォーマットで書き出したいので、EXCELテンプレートを事前に用意しました。

・参照設定:
<?php
namespace App\Controller;
use Cake\ORM\TableRegistry;
use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;

require_once(realpath(TMP).DS."classes".DS."PHPExcel.php");
require_once(realpath(TMP).DS."classes".DS."PHPExcel".DS."IOFactory.php");

use PHPExcel_IOFactory;

・エクセルテンプレート置く場所:
tmp/excel/template.xlsx

・ソース

public function download ($id=null){

$target = $this->Targets->get($id, 
        [ 'contain' => []
          ]);

 // データを配置

$manager_id=$target->manager_id;
$year_number=$GLOBALS["current_year"];
$sec=$GLOBALS["current_sec"];

$shainjname=AppController::cal_user_janame($manager_id);

// 入出力の情報設定
$driPath    = realpath(TMP) . "/excel/";
$inputPath  = $driPath . "template.xlsx";
$sheetName  = "data_sheet";

$outputFile = "output_".$shainjname.date('YmdHis'). ".xlsx";

$outputPath = $driPath . $outputFile;

// Excalファイル作成
$reader = PHPExcel_IOFactory::createReader('Excel2007');
$book  = $reader->load($inputPath);
$sheet  = $book->getSheetByName($sheetName);

if  ($sec == 1) {
    $jasec="上期";
} else {
    $jasec="下期";
}

 $sheet->setCellValue( "BY1", strval($year_number)."年度".$jasec);

 $connection = ConnectionManager::get('default');

//タイトル情報
//managers テーブルのデータ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

$statementm = "SELECT * FROM managers WHERE managers.id = '$manager_id'";
$stmtm = $connection->execute( $statementm)->fetchAll('assoc');

foreach ($stmtm as $row) {

    $sheet->setCellValue( "A3", $shainid);
   ・・・    
}


 //honbu_targets テーブルのデータ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

$hstatement = "SELECT * FROM honbu_targets WHERE honbu_targets.year_number = '$year_number' and honbu_targets.section = '$sec' and honbu_targets.honbu_id = '$honbu_id' order by subid";

  $hstmt = $connection->execute( $hstatement)->fetchAll('assoc');

         $h=0;
         $hfirstLine=7;

        foreach ($hstmt as $hrow) {

            $hcellLine = $hfirstLine +$h;

            $hcellB="B" .strval($hcellLine);

            $honbu_target=$hrow['target'] ;

            $sheet->setCellValue( $hcellB,  $honbu_target);

            $h=$h+3;
        }


//bumon_targets テーブルのデータ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓


  $jstatement = "SELECT * FROM bumon_targets WHERE bumon_targets.year_number = '$year_number' and bumon_targets.section = '$sec' and bumon_targets.bumon_id = '$bumon_id' order by subid";

  $jstmt = $connection->execute( $jstatement)->fetchAll('assoc');

         $j=0;
         $jfirstLine=7;

        foreach ($jstmt as $jrow) {

            $jcellLine = $jfirstLine +$j;

            $jcellAB="AB" .strval($jcellLine);

            $bumon_target=$jrow['target'] ;

            $sheet->setCellValue( $jcellAB,  $bumon_target);

            $j=$j+3;
        }




//targets テーブルのデータ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓



  $statement = "SELECT * FROM targets WHERE targets.year_number = '$year_number' and targets.sec = '$sec' and  targets.manager_id = '$manager_id' order by subid";

  $stmt = $connection->execute( $statement)->fetchAll('assoc');

         $i=0;
         $firstLine=27;

        foreach ($stmt as $row) {

            $cellLine = $firstLine +$i;

            $cellB="B" .strval($cellLine);
            $cellO="O" .strval($cellLine);
            ・・・

            $mokuhyou=$row['target'] ;
            $plan=$row['plan'] ;
           ・・・

            $sheet->setCellValue( $cellB, $mokuhyou);
            $sheet->setCellValue( $cellO, $plan);
            $sheet->setCellValue( $cellAB, $weight);
            ・・・・

            $i=$i+4;
         }

          //targets テーブルのデータ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

// 保存
$book->setActiveSheetIndex(0);
$writer = PHPExcel_IOFactory::createWriter($book, 'Excel2007');
$writer->save($outputPath);


 // ダウンロード

header('Content-Type: application/octet-stream');

ob_end_clean();//バッファのゴミ捨て
header('Content-Disposition: attachment;filename="' . $outputFile . '"');
header('Cache-Control: max-age=0');


$book->setActiveSheetIndex(0);
$writer = PHPExcel_IOFactory::createWriter($book, 'Excel2007');


$writer->save('php://output'); 
exit;

return $this->redirect(['action' => 'index']);

}

10、サーバー環境構築
CPIのサーバーを利用する。下記サイトを参照しました、
 CPIサーバでCakePHP:
   http://g37.jp/2015/03/use-cakephp-in-cpi-server-vol1/

   /html/に、プロジェクトフォルダを丸ごとアップします。

※サーバーパス、ファイル名などは、大文字小文字を区別するので、気をつけてください。

11、Templateビューの編集

・自動作成のコード

<?= $this->Html->link(('テンプレート・ダウンロード'),['controller' => 'Targets', 'action' => 'get_template'])?>
<?= $this->Html->link(('アップロード'), ['controller' => 'Uploads', 'action' => 'index']) ?>
 
・PHPコード入れ
<?php
if ($GLOBALS['current_rank_id'] < 4 or $GLOBALS['current_rank_id'] == 7 ) {
echo "",$this->Html->link(__('AAAA'), ['controller' => 'BumonTargets', 'action' => 'index']),"" ;
}
?>

・php endforeach/php endifの書き方

<?php if ($GLOBALS['current_rank_id'] < 7 and $GLOBALS['current_rank_id'] >2) : ?>

      <h5>本人</h5> 
       <table cellpadding="0" cellspacing="0">

             <?php foreach ($homes_self as $home_self): ?>    
              <tr>  
                <td><?= $home_self->has('manager') ? $this->Html->link($home_self->manager->name, ['controller' =>             'Targets', 'action' => 'index', $home_self->manager->id]) : '' ?></td>
                <td><?= h($home_self->target_put) ?></td>
                <td><?= h($home_self->dir_permission) ?></td>         
                <td><?= h($home_self->self_put) ?></td>                
                 ...

                <td class="actions">
                    <?= $this->Html->link(__('編集'), ['action' => 'edit', $home_self->id]) ?>
                </td>

             </tr>
             <?php endforeach; ?>
        </table>   

<?php endif; ?>