Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

コマンドライン

参考
yamaimo.hatenablog.jp


コンパイルする場合はswiftcを使う。

$ swiftc -help
OVERVIEW: Swift compiler

USAGE: swiftc [options] <inputs>

MODES:
  -dump-ast        Parse and type-check input file(s) and dump AST(s)
  -dump-parse      Parse input file(s) and dump AST(s)
  -dump-scope-maps <expanded-or-list-of-line:column>
                   Parse and type-check input file(s) and dump the scope map(s)
  -dump-type-refinement-contexts
                   Type-check input file(s) and dump type refinement contexts(s)
  -emit-assembly   Emit assembly file(s) (-S)
  -emit-bc         Emit LLVM BC file(s)
  -emit-executable Emit a linked executable
  -emit-ir         Emit LLVM IR file(s)
  -emit-library    Emit a linked library
  -emit-object     Emit object file(s) (-c)
  -emit-sibgen     Emit serialized AST + raw SIL file(s)
  -emit-sib        Emit serialized AST + canonical SIL file(s)
  -emit-silgen     Emit raw SIL file(s)
  -emit-sil        Emit canonical SIL file(s)
  -parse           Parse input file(s)
  -print-ast       Parse and type-check input file(s) and pretty print AST(s)
  -typecheck       Parse and type-check input file(s)

OPTIONS:
  -application-extension  Restrict code to those available for App Extensions
  -assert-config <value>  Specify the assert_configuration replacement. Possible values are Debug, Release, Unchecked, DisableReplacement.
  -continue-building-after-errors
                          Continue building, even after errors are encountered
  -driver-time-compilation
                          Prints the total time it took to execute all compilation tasks
  -D <value>              Marks a conditional compilation flag as true
  -embed-bitcode-marker   Embed placeholder LLVM IR data as a marker
  -embed-bitcode          Embed LLVM IR bitcode as data
  -emit-dependencies      Emit basic Make-compatible dependencies files
  -emit-module-path <path>
                          Emit an importable module to <path>
  -emit-module            Emit an importable module
  -emit-objc-header-path <path>
                          Emit an Objective-C header file to <path>
  -emit-objc-header       Emit an Objective-C header file
  -fixit-all              Apply all fixits from diagnostics without any filtering
  -fixit-code             Get compiler fixits as code edits
  -framework <value>      Specifies a framework which should be linked against
  -F <value>              Add directory to framework search path
  -gdwarf-types           Emit full DWARF type info.
  -gline-tables-only      Emit minimal debug info for backtraces only
  -gnone                  Don't emit debug info
  -g                      Emit debug info. This is the preferred setting for debugging with LLDB.
  -help                   Display available options
  -import-underlying-module
                          Implicitly imports the Objective-C half of a module
  -index-store-path <path>
                          Store indexing data to <path>
  -I <value>              Add directory to the import search path
  -j <n>                  Number of commands to execute in parallel
  -L <value>              Add directory to library link search path
  -l<value>               Specifies a library which should be linked against
  -module-cache-path <value>
                          Specifies the Clang module cache path
  -module-link-name <value>
                          Library to link against when using this module
  -module-name <value>    Name of the module to build
  -nostdimport            Don't search the standard library import path for modules
  -num-threads <n>        Enable multi-threading and specify number of threads
  -Onone                  Compile without any optimization
  -Ounchecked             Compile with optimizations and remove runtime safety checks
  -output-file-map <path> A file which specifies the location of outputs
  -O                      Compile with optimizations
  -o <file>               Write output to <file>
  -parse-as-library       Parse the input file(s) as libraries, not scripts
  -parse-sil              Parse the input file as SIL code, not Swift source
  -parseable-output       Emit textual output in a parseable format
  -profile-coverage-mapping
                          Generate coverage data for use with profiled execution counts
  -profile-generate       Generate instrumented code to collect execution counts
  -sanitize-coverage=<type>
                          Specify the type of coverage instrumentation for Sanitizers and additional options separated by commas
  -sanitize=<check>       Turn on runtime checks for erroneous behavior.
  -save-temps             Save intermediate compilation results
  -sdk <sdk>              Compile against <sdk>
  -serialize-diagnostics  Serialize diagnostics in a binary format
  -static-executable      Statically link the executable
  -static-stdlib          Statically link the Swift standard library
  -suppress-warnings      Suppress all warnings
  -swift-version <vers>   Interpret input according to a specific Swift language version number
  -target-cpu <value>     Generate code for a particular CPU variant
  -target <value>         Generate code for the given target
  -tools-directory <directory>
                          Look for external executables (ld, clang, binutils) in <directory>
  -use-ld=<value>         Specifies the linker to be used
  -version                Print version information and exit
  -v                      Show commands to run and use verbose output
  -warnings-as-errors     Treat warnings as errors
  -whole-module-optimization
                          Optimize input files together instead of individually
  -Xcc <arg>              Pass <arg> to the C/C++/Objective-C compiler
  -Xlinker <value>        Specifies an option which should be passed to the linker

そしてswiftというコマンドもある。

$ swift -h
OVERVIEW: Swift compiler

USAGE: swift [options] <inputs>

OPTIONS:
  -assert-config <value> Specify the assert_configuration replacement. Possible values are Debug, Release, Unchecked, DisableReplacement.
  -continue-building-after-errors
                         Continue building, even after errors are encountered
  -D <value>             Marks a conditional compilation flag as true
  -framework <value>     Specifies a framework which should be linked against
  -F <value>             Add directory to framework search path
  -gdwarf-types          Emit full DWARF type info.
  -gline-tables-only     Emit minimal debug info for backtraces only
  -gnone                 Don't emit debug info
  -g                     Emit debug info. This is the preferred setting for debugging with LLDB.
  -help                  Display available options
  -index-store-path <path>
                         Store indexing data to <path>
  -I <value>             Add directory to the import search path
  -j <n>                 Number of commands to execute in parallel
  -L <value>             Add directory to library link search path
  -l<value>              Specifies a library which should be linked against
  -module-cache-path <value>
                         Specifies the Clang module cache path
  -module-link-name <value>
                         Library to link against when using this module
  -module-name <value>   Name of the module to build
  -nostdimport           Don't search the standard library import path for modules
  -num-threads <n>       Enable multi-threading and specify number of threads
  -Onone                 Compile without any optimization
  -Ounchecked            Compile with optimizations and remove runtime safety checks
  -O                     Compile with optimizations
  -sdk <sdk>             Compile against <sdk>
  -static-executable     Statically link the executable
  -static-stdlib         Statically link the Swift standard library
  -suppress-warnings     Suppress all warnings
  -swift-version <vers>  Interpret input according to a specific Swift language version number
  -target-cpu <value>    Generate code for a particular CPU variant
  -target <value>        Generate code for the given target
  -use-ld=<value>        Specifies the linker to be used
  -version               Print version information and exit
  -v                     Show commands to run and use verbose output
  -warnings-as-errors    Treat warnings as errors
  -Xcc <arg>             Pass <arg> to the C/C++/Objective-C compiler
  -Xlinker <value>       Specifies an option which should be passed to the linker

Swiftは対話モードで実行できる。

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> 3+2
$R0: Int = 5
  2> class A { 
  3.     var hoge:Int? = nil 
  4.     func hello() { 
  5.         print("hello \(hoge)") 
  6.     } 
  7. } 
  8> let a = A()
a: A = {
  hoge = nil
}
  9> a.hoge = 100
 10> a.hello()
hello Optional(100)
 11>  

文字列ストリーム風

以下でStream(Array(src.characters))としてやれば文字列stream風になる。

    class Stream<T> {
        let m_value:[T]
        var count = 0
        init(_ v:[T]) {
            m_value = v
        }
        
        func get()->T? {
            if count < m_value.count {
                let ret = m_value[count]
                count = count + 1
                print("\(ret)")
                return ret
                
            } else {
                return nil
            }
        }
        
        func unget() {
            count = count - 1
            print("unget")
            if count < 0 {
                count = count + 1
            }
        }
    }

GCDの例

SwiftでGCDのgroup等の使い方のサンプルを書いてみた。

//
//  ViewController.swift
//  GCDSample
//
//  Created by KatagiriSo on 2017/09/19.
//  Copyright © 2017年 RodhosSoft. All rights reserved.
//

import UIKit

class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource{
    
    
    struct Menu {
        let name:String
    }
    
    let menu:[Menu] = [Menu(name: NSStringFromSelector(#selector(AsyncBarrier))),
                       Menu(name: NSStringFromSelector(#selector(GroupWait))),
                       Menu(name: NSStringFromSelector(#selector(GroupNotify))),
                       Menu(name: NSStringFromSelector(#selector(GroupEnterLeave))),
                       Menu(name: NSStringFromSelector(#selector(SemaphoExample)))

        
                       ]
    
    func makeEqualConstraint(item:Any, toItem:Any, attribute:NSLayoutAttribute) ->  NSLayoutConstraint{
        return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .equal, toItem: toItem, attribute: attribute, multiplier: 1.0, constant: 0)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let tableView:UITableView = UITableView(frame: self.view.bounds)
        tableView.delegate = self
        tableView.dataSource = self
        
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")

        
        self.view.addSubview(tableView)
        
        
        let l = makeEqualConstraint(item: tableView, toItem: self.view, attribute: .left)
        let r = makeEqualConstraint(item: tableView, toItem: self.view, attribute: .right)
        let t = makeEqualConstraint(item: tableView, toItem: self.view, attribute: .top)
        let b = makeEqualConstraint(item: tableView, toItem: self.view, attribute: .bottom)
        
        l.isActive = true
        r.isActive = true
        t.isActive = true
        b.isActive = true

    }
    
    

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menu.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = menu[indexPath.row].name
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let selector = NSSelectorFromString(menu[indexPath.row].name)
        self.perform(selector)
    }
    
    func AsyncBarrier() {
        print("\(#function)")
        
        let queue = DispatchQueue(label: "asyncBarrierTest")
        [1,2,3,4,5,6,7,8,9,10].forEach { n in
            queue.async {
                print("done \(n)")
            }
        }
        
        queue.async(flags:.barrier) {
            print("all done")
        }
        
        print("\(#function) end")
    }
    
    func GroupWait() {
        print("\(#function)")
        
        let queue = DispatchQueue(label: "groupWaitTest")
        let group = DispatchGroup()
        
        for n in 1...100 {
            queue.async(group: group) {
                print("done \(n)")
            }
        }
        
        print("group.wait")
        let _ = group.wait(timeout: DispatchTime.distantFuture)
        
        
        print("\(#function) end")
    }
    
    func GroupNotify() {
        print("\(#function)")
        
        let queue = DispatchQueue(label: "GroupNotify")
        let group = DispatchGroup()
        
        for n in 1...100 {
            queue.async(group: group) {
                print("done \(n)")
            }
        }
        
        group.notify(queue: queue) {
            print("done")
        }
        
        print("\(#function) end")
    }
    
    func GroupEnterLeave() {
        print("\(#function)")
        
        let queue = DispatchQueue(label: "GroupNotify")
        let group = DispatchGroup()
        
        for n in 1...100 {
            group.enter()
            queue.async {
                print("done \(n)")
                group.leave()
            }
        }
        
        group.notify(queue: queue) {
            print("done")
        }
        
        print("\(#function) end")
    }
    
    func SemaphoExample() {
        
        print("\(#function)")
        
        let semapho = DispatchSemaphore(value: 0)
        
//        semapho.wait()

        DispatchQueue.global().async {
            for n in 1...100 {
                print("count \(n)")
            }
            
            semapho.signal()
        }
        
        
        print("wait")
        semapho.wait()
        
        
        print("\(#function) end")
    }

    


}

View

rederによってViewがレンダリングされる。その部分をみてみる。

public function render($view = null, $layout = null)
    {
// すでにレンダリングされているなら終わり
        if ($this->hasRendered) {
            return null;
        }

// レイアウトがメソッドの引数に指定されているならそれをレイアウトとして使う
        $defaultLayout = null;
        if ($layout !== null) {
            $defaultLayout = $this->layout;
            $this->layout = $layout;
        }

        $viewFileName = $view !== false ? $this->_getViewFileName($view) : null;

        if ($viewFileName) {
            $this->_currentType = static::TYPE_TEMPLATE;
/// レンダリングイベント通知
            $this->dispatchEvent('View.beforeRender', [$viewFileName]);

/// _render関数でレイアウトし、ブロックのcontentとしてsetする。
            $this->Blocks->set('content', $this->_render($viewFileName));

/// レンダリング終了通知
            $this->dispatchEvent('View.afterRender', [$viewFileName]);
        }

/// レウアウトがあるならrenderLayoutでレンダリングし、ブロックのcontentとしてセットする。
        if ($this->layout && $this->autoLayout) {
            $this->Blocks->set('content', $this->renderLayout('', $this->layout));
        }
        if ($layout !== null) {
            $this->layout = $defaultLayout;
        }

        $this->hasRendered = true;

/// ブロックのcontentを取得し返却する。
        return $this->Blocks->get('content');
    }


_render関数、ここが本体になる。テンプレートの継承などもここで解決する。

    protected function _render($viewFile, $data = [])
    {
// 引数で$dataが指定されていなければviewVarsを$dataとして使う。
        if (empty($data)) {
            $data = $this->viewVars;
        }
        $this->_current = $viewFile;
        $initialBlocks = count($this->Blocks->unclosed());

// イベント通知
        $this->dispatchEvent('View.beforeRenderFile', [$viewFile]);

// テンプレートを_evaluateする。ここでファイル内のコードが実行される?
        $content = $this->_evaluate($viewFile, $data);

// イベント通知
        $afterEvent = $this->dispatchEvent('View.afterRenderFile', [$viewFile, $content]);
        if ($afterEvent->getResult() !== null) {
            $content = $afterEvent->getResult();
        }

// ここで継承しているテンプレートがあればアサインし
        if (isset($this->_parents[$viewFile])) {
            $this->_stack[] = $this->fetch('content');
            $this->assign('content', $content);

//  親のレンダリング
            $content = $this->_render($this->_parents[$viewFile]);
            $this->assign('content', array_pop($this->_stack));
        }

        $remainingBlocks = count($this->Blocks->unclosed());

        if ($initialBlocks !== $remainingBlocks) {
            throw new LogicException(sprintf(
                'The "%s" block was left open. Blocks are not allowed to cross files.',
                $this->Blocks->active()
            ));
        }

        return $content;
    }


$this->Blocksのところ、ビューブロックをおさえる必要がある。

ViewBuilder

ビューを作る。

build()のところで作っている。

public function build($vars = [], ServerRequest $request = null, Response $response = null, EventManager $events = null)
    {
        $className = $this->_className;
        if ($className === null) {
            $className = App::className('App', 'View', 'View') ?: 'Cake\View\View';
        }
        if ($className === 'View') {
            $className = App::className($className, 'View');
        } else {
            $className = App::className($className, 'View', 'View');
        }
        if (!$className) {
            throw new MissingViewException(['class' => $this->_className]);
        }

        $data = [
            'name' => $this->_name,
            'templatePath' => $this->_templatePath,
            'template' => $this->_template,
            'plugin' => $this->_plugin,
            'theme' => $this->_theme,
            'layout' => $this->_layout,
            'autoLayout' => $this->_autoLayout,
            'layoutPath' => $this->_layoutPath,
            'helpers' => $this->_helpers,
            'viewVars' => $vars,
        ];
        $data += $this->_options;

        return new $className($request, $response, $events, $data);
    }

builderのbuild()はViewVarsTraitのcreateView($viewClass = null)で呼ばれている。

ViewVarsTraitはControllerで使われている。

Controllerのrender($view = null, $layout = null)関数。

    public function render($view = null, $layout = null)
    {
// ビュービルダーを取得
        $builder = $this->viewBuilder();
// ビルダーにテンプレートパスが設定されてないならコントローラの_viewPath()で設定する。
        if (!$builder->getTemplatePath()) {
            $builder->setTemplatePath($this->_viewPath());
        }
// リクエストにbareパラムがあるならAutoLayoutを切る
        if ($this->request->getParam('bare')) {
            $builder->enableAutoLayout(false);
        }
        $builder->getClassName($this->viewClass);
// コントローラのautoRenderを切る
        $this->autoRender = false;

// beforeRenderイベントを通知
        $event = $this->dispatchEvent('Controller.beforeRender');
        if ($event->getResult() instanceof Response) {
            return $event->getResult();
        }
        if ($event->isStopped()) {
            return $this->response;
        }

// ビルダーにテンプレートが設定されなく、リクエストにアクションが設定されているなら、そのアクションからテンプレートを引っ張ってきて設定する。
        if ($builder->getTemplate() === null && $this->request->getParam('action')) {
            $builder->setTemplate($this->request->getParam('action'));
        }
// ビューを生成する。
        $this->View = $this->createView();

// ビューをレイアウトを使ってレンダリングする。
        $this->response->body($this->View->render($view, $layout));

        return $this->response;
    }

renderはControllerのactionで明示的に呼ぶこともできるがautoRenderを設定しているときはactionが呼ばれたときに自動的に呼ばれている。その機構はActionDispatcherの_invoke(Controller $controller)にある。

protected function _invoke(Controller $controller)
    {
//  invokeControllerイベントを通知する。
        $this->dispatchEvent('Dispatcher.invokeController', ['controller' => $controller]);

        $result = $controller->startupProcess();
        if ($result instanceof Response) {
            return $result;
        }

// コントローラのinvokeActionを呼ぶ ここでコントローラのアクションが呼ばれる。
        $response = $controller->invokeAction();

// アクションからのレスポンスがなくてautoRenderがtrueならレンダリングしてそのresponseを返却する。
        if ($response !== null && !($response instanceof Response)) {
            throw new LogicException('Controller actions can only return Cake\Http\Response or null.');
        }

        if (!$response && $controller->autoRender) {
            $response = $controller->render();
        } elseif (!$response) {
            $response = $controller->response;
        }

        $result = $controller->shutdownProcess();
        if ($result instanceof Response) {
            return $result;
        }

        return $response;
    }

この_invoke関数はdispatch(ServerRequest $request, Response $response)関数から呼ばれる。

public function dispatch(ServerRequest $request, Response $response)
    {
        if (Router::getRequest(true) !== $request) {
            Router::pushRequest($request);
        }

//  beforeDispatchを通知
        $beforeEvent = $this->dispatchEvent('Dispatcher.beforeDispatch', compact('request', 'response'));

        $request = $beforeEvent->getData('request');
        if ($beforeEvent->getResult() instanceof Response) {
            return $beforeEvent->getResult();
        }

// コントローラを生成しているらしい。。

        // Use the controller built by an beforeDispatch
        // event handler if there is one.
        if ($beforeEvent->getData('controller') instanceof Controller) {
            $controller = $beforeEvent->getData('controller');
        } else {
            $controller = $this->factory->create($request, $response);
        }

// 生成したコントローラに対して_invokeを実行。
        $response = $this->_invoke($controller);

// requestにreturnが設定されていたらresponseを返却
        if (isset($request->params['return'])) {
            return $response;
        }

// afterDispatchを通知
        $afterEvent = $this->dispatchEvent('Dispatcher.afterDispatch', compact('request', 'response'));

// 
        return $afterEvent->getData('response');
    }

このdispatchはDispatcherのdispatchで呼ばれる。

    public function dispatch(ServerRequest $request, Response $response)
    {
        $actionDispatcher = new ActionDispatcher(null, $this->eventManager(), $this->_filters);
        $response = $actionDispatcher->dispatch($request, $response);
        if (isset($request->params['return'])) {
            return $response->body();
        }

        return $response->send();
    }

DispatcherはDispatcherFactoryのcreate関数で作られる。

    public static function create()
    {
        $dispatcher = new Dispatcher();
        foreach (static::$_stack as $middleware) {
            $dispatcher->addFilter($middleware);
        }

        return $dispatcher;
    }

アクションがどのように呼ばれるのか

このあたりで、CakePHPでどのようにアクションが呼ばれるのかについて調べていることを自覚した。

webrootのindex.phoを調べてみる。

// Bind your application to the server.
$server = new Server(new Application(dirname(__DIR__) . '/config'));

// Run the request/response through the application
// and emit the response.
$server->emit($server->run());

このあたりがポイントか。このApplicationはBaseApplicationを継承している。BaseApplicationではgetDispatcherでActionDispatcherを作り、__invokeでdispatchしている。

    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
    {
        return $this->getDispatcher()->dispatch($request, $response);
    }


というわけで

BaseApplicationの__invokeでActionDispatcherがdispatchし、その関数内でコントローラに_invokeする。
_invokeはautoRenderがtrueだとコントローラのrender()関数を呼び、render()関数はビュービルダーを使ってビューをビルドする。という流れのようだ。

Server

サーバは以下の方法でRunnerにApplicationとミドルウェアを追加してrunし、Runnerは__invokeして回るのでリクエストが処理されていくようだ。

public function run(ServerRequestInterface $request = null, ResponseInterface $response = null)
    {
        $this->app->bootstrap();
        $response = $response ?: new Response();

// リクエスト取得
        $request = $request ?: ServerRequestFactory::fromGlobals();

// ミドルウェア
        $middleware = $this->app->middleware(new MiddlewareQueue());
        if (!($middleware instanceof MiddlewareQueue)) {
            throw new RuntimeException('The application `middleware` method did not return a middleware queue.');
        }
// ミドルウェア生成イベント通知
        $this->dispatchEvent('Server.buildMiddleware', ['middleware' => $middleware]);

// まずミドルウェアとしてApplicationを登録
        $middleware->add($this->app);

// runnerにrunしレスポンスを取得
        $response = $this->runner->run($middleware, $request, $response);

        if (!($response instanceof ResponseInterface)) {
            throw new RuntimeException(sprintf(
                'Application did not create a response. Got "%s" instead.',
                is_object($response) ? get_class($response) : $response
            ));
        }

// レスポンスを返却
        return $response;
    }

このrunはMiddlewareDispatcherにてexecute($request)されるようだ。

public function execute($request)
    {
        try {
            $reflect = new ReflectionClass($this->_class);
            $app = $reflect->newInstanceArgs($this->_constructorArgs);
        } catch (ReflectionException $e) {
            throw new LogicException(sprintf(
                'Cannot load "%s" for use in integration testing.',
                $this->_class
            ));
        }

        // Spy on the controller using the initialize hook instead
        // of the dispatcher hooks as those will be going away one day.
        EventManager::instance()->on(
            'Controller.initialize',
            [$this->_test, 'controllerSpy']
        );

        $server = new Server($app);
        $psrRequest = $this->_createRequest($request);

        return $server->run($psrRequest);
    }

View

AppViewが基底でViewを継承している。

自作のヘルパーなどはinitialize内で $this->loadHelper('MyUtils');してやることで使えるようになる。

View

EventDispatcherInterfaceを実装している。

使用しているtrait

CellTrait

EventDispatcherTrait;

LogTrait;

RequestActionTrait;

ViewVarsTrait;

変数

_helpers

Blocks

plugin

name ビューを作ったコントローラの名前

helpers ビルトインされているヘルパー

templatePath テンプレートのパス

template テンプレートの名前

layout 使用しているレイアウト

layoutPath 使用しているレイアウトの名前

autoLayout 自動レイアウトのonoff

_ext テンプレートの拡張子 デフォルトはctp

subDir

theme ビューのテーマ

hasRendered ビューがすでにレンダリングされているか

uuids 生成されたDOMのuuid

request

response

elementCache

_passedVars 関連するコントローラからの変数

_paths

_pathsForPlugin

_parents ビューの継承元。View::extend()で使用。

_current

_currentType

_stack ネストされたテンプレート。View::extend()で使用。

TYPE_TEMPLATE

TYPE_ELEMENT

TYPE_LAYOUT

メソッド

initialize()

templatePath($path = null) テンプレートのセットとゲット

layoutPath($path = null) レイアウトのセットとゲット

autoLayout($autoLayout = null)

theme($theme = null)

template($name = null)

layout($name = null)

element($name, array $data = , array $options = )  エレメントの描画。_renderElementを使う。

cache(callable $block, array $options = )

elementExists($name) エレメントがあるかのチェック

render($view = null, $layout = null) 与えられたテンプレートとレイアウトでレンダリングする。

renderLayout($content, $layout = null) レイアウトのレンダリング

getVars() $this->viewVarsの名前を返す

get($var, $default = null) view変数を取得

blocks() ビューブロックのキーを返す。$this->Blocks->keys();

start($name) ビューブロックのスタート $this->Blocks->start($name);

append($name, $value = null) ビューブロックの追加 $this->Blocks->concat($name, $value);

prepend($name, $value) $this->Blocks->concat($name, $value, ViewBlock::PREPEND);

assign($name, $value) ビューブロックのセット $this->Blocks->set($name, $value);

reset($name) ビューブロックのリセット $this->assign($name, '');

fetch($name, $default = '') ビューブロックのコンテンツを取得 $this->Blocks->get($name, $default);

end() ビューブロックのエンド $this->Blocks->end();

exists($name) ビューブロックの存在確認 $this->Blocks->exists($name);

extend($name)  テンプレートの継承

uuid($object, $url) uuidの取得

getCurrentType()

__get($name)

__set($name, $value)

loadHelpers() ヘルパーの読み込み

_render($viewFile, $data = ) レンダリング

_evaluate($viewFile, $dataForView)

helpers() ヘルパー

loadHelper($name, array $config = []) ヘルパーの読み込み

_getViewFileName($name = null)

_inflectViewFileName($name)

_checkFilePath($file, $path)

pluginSplit($name, $fallback = true)

_getLayoutFileName($name = null)

_getElementFileName($name, $pluginCheck = true)

_getSubPaths($basePath)

_paths($plugin = null, $cached = true)

_elementCache($name, $data, $options)

_renderElement($file, $data, $options)

flexbox その2

flexboxを改めてやる。以下のサイトの記事を読んだ。

coliss.com

flexアイテムとflexコンテナ

flexコンテナは多数のflexアイテムを内包する。flexコンテナにしたい要素に display: flex;を設定する。
すると子要素は自動的にflexアイテムになる。

並べる方向

flex-direction: row; で横方向に並べる。 row-reverseなら右から左になる。columnで上から下。column-reverseで下から上。

1行に収めたい

flex-wrap: nowrap; で1行に収める。flexアイテムの幅は一行に収まるように縮まる。

flex-wrap: wrap;だと複数行

まとめて設定

flex-flow: row nowrap;

右づめで表示したい。

justify-content: flex-end; でdirectionがrowなら右づめになる。flex-startなら左づめ、centerなら中央、space-betweenなら等間隔に間をあけて表示される。space-aroundなら端っこにも空間があいた等間隔。

横にならべておいてアイテムの高さはコンテナいっぱいにひろげたい。

横に並べている(row)のときの縦をクロス軸と呼ぶ。
align-items: stretch; を設定すれば良い。
縦方向は上詰めにしたい場合はalign-items: flex-start;。下詰めにしたいときはflex-end。縦方向に中央に配置したい場合はcenter。baselaineに沿わせるならbaseline。

横にならべておいて、複数行の行間を調整したい。

align-content: stretch; コンテナの高さに基づいて均等配置。flex-startなら上からつまる。flex-endなら下からつまる。centerは中央。上端から下端で等間隔ならspace-between。上端と下端で端っこにも空間があいた等間隔ならspace-around。

アイテムの並び順

アイテムに対して order: 2; 等と設定。

アイテムの幅の比率

アイテムに対して flex-grow: 1; 等と設定。デフォルトは0
他のアイテムに対して縮まるかはflex-shrink: 1;等と設定。デフォルトは1

アイテムの幅の設定

アイテムに対してflex-basis: 350px; で350に、flex-basis: auto;なら自動計算。

glow, shrink, basisはまとめてflex:で指定できる。

デフォルト値なら flex: 0 1 auto;

アイテムを指定して並べ方を指定

align-self

URLヘルパ

URLを作る。

$this->Url->build(['action' => 'home', $article->id])

/kagero3/articles/view/1

ができる。

エレメントとHTMLヘルパ等と組み合わせて次のようなものが作れた。

<?= $this->Html->tag( "a",
    $this->Element( "agora_card", 
                    [
                        "title" => $article->title,
                        "body" => $article->body
                    ]
                )
    , ["href" => 
        $this->Url->build(['action' => 'home', $article->id])
        ]
    ) 
?>
<a url="/kagero3/articles/view/1"><div style="width:200px; height:200px; background-color:white;">
    <div>
        <p>
            タイトル        </p>
    </div>
    <div>
        <p>
            内容        </p>
    </div>
</div></a>

ちょっと面白くなってきた。

HTMLヘルパー その2

以下を参考に色々さわっている。
qiita.com
CakePHP 1.3 - Htmlヘルパー


スクリプトタグ

<?= $this->Html->script('myscripts'); ?>
<script src="/kagero3/js/myscripts.js"></script>

CSS

<?= $this->Html->css( 'mycss'); ?>
<link rel="stylesheet" href="/kagero3/css/mycss.css"/>

画像リンク

<?= $this->Html->image( 'cake.power.gif',
                        ["alt" => "cake.power",
                         "url" => [ "controller" => "Articles",
                                    "action" => "home",
                                    "1"]
                        ]
                    ); ?>
<a href="/kagero3/articles/home/1"><img src="/kagero3/img/cake.power.gif" alt="cake.power"/></a>

urlを指定しないと単純にimageタグができる。

<?= $this->Html->image( 'cake.power.gif',
                        ["alt" => "cake.power"]
                    ); ?>
<img src="/kagero3/img/cake.power.gif" alt="cake.power"/>

タグ

タグ自体を指定して生成することもできる。

<?= $this->Html->tag( 'div',
                        'hello',
                        ['class' => 'classA']
                    ); ?>
<div class="classA">hello</div>


よって、タグの入れ子も表現できる。

<?= $this->Html->tag('div',$this->Html->tag( 'p','hello'),['class' => 'classA']); ?>
<div class="classA"><p>hello</p></div>

HTMLヘルパー

qiita.com

単純にリンク

<?= $this->Html->link("hello","http://rodhos.info/") ?>

は次のように変換される。

<a href="http://rodhos.info/">hello</a>

つまり、第1引数が表示する文字で、第2引数がURL。
第2引数は以下のように連想配列で指定することもできる。

<?= $this->Html->link(__('View'), ['action' => 'view', $article->id]) ?>
<a href="/kagero3/articles/view/1">View</a>

もう一つ例として

<?= $this->Html->link("hello",[ "controller" => "Articles", 
                                "action" => "home",
                                "1"]) ?>

は次のように変換される。

<a href="/kagero3/articles/home/1">hello</a>

第3引数

第3引数を指定するとaタグに属性をつけられる。

<?= $this->Html->link(  "hello",
                        "http://rodhos.info/",
                        ["class" => "button"]) ?>

は次のようになる。

<a href="http://rodhos.info/" class="button">hello</a>

テーブルのところ

CakePHPのbakeで作られたテーブル

    <table cellpadding="0" cellspacing="0">
        <thead>
            <tr>
                <th scope="col"><?= $this->Paginator->sort('id') ?></th>
                <th scope="col"><?= $this->Paginator->sort('title') ?></th>
                <th scope="col"><?= $this->Paginator->sort('category_id') ?></th>
                <th scope="col"><?= $this->Paginator->sort('avatar_id') ?></th>
                <th scope="col"><?= $this->Paginator->sort('created') ?></th>
                <th scope="col"><?= $this->Paginator->sort('modified') ?></th>
                <th scope="col" class="actions"><?= __('Actions') ?></th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($articles as $article): ?>
            <tr>
                <td><?= $this->Number->format($article->id) ?></td>
                <td><?= h($article->title) ?></td>
                <td><?= $article->has('category') ? $this->Html->link($article->category->name, ['controller' => 'Categories', 'action' => 'view', $article->category->id]) : '' ?></td>
                <td><?= $article->has('avatar') ? $this->Html->link($article->avatar->name, ['controller' => 'Avatars', 'action' => 'view', $article->avatar->id]) : '' ?></td>
                <td><?= h($article->created) ?></td>
                <td><?= h($article->modified) ?></td>
                <td class="actions">
                    <?= $this->Html->link(__('View'), ['action' => 'view', $article->id]) ?>
                    <?= $this->Html->link(__('Edit'), ['action' => 'edit', $article->id]) ?>
                    <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $article->id], ['confirm' => __('Are you sure you want to delete # {0}?', $article->id)]) ?>
                </td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>