帰ってきた!平成最後のオレオレフレームワークの作り方

271fad8d53cd1f12f2b4b6d38e3d7bd3?s=47 uzulla
March 31, 2019

 帰ってきた!平成最後のオレオレフレームワークの作り方

PHPerKaigi 2019
2019/03/31 Track A
uzulla

271fad8d53cd1f12f2b4b6d38e3d7bd3?s=128

uzulla

March 31, 2019
Tweet

Transcript

  1. ؼ͖ͬͯͨʂ ฏ੒࠷ޙͷ ΦϨΦϨϑϨʔϜϫʔΫͷ ࡞Γํ » PHPerKaigi 2019 » 2019/03/22 »

    @uzulla
  2. ʮؼ͖ͬͯͨʯʁ » ʮPHPerਓੜɺҰ౓͸ϑϨʔϜϫʔΫΛ࡞͓ͬͯ͜ ͏ʂʯ » PHPΧϯϑΝϨϯε๺ւಓ 2016 » https://speakerdeck.com/uzulla/phperren- sheng-du-hahuremuwakuwozuo-tuteokou

    » ࣍ͷϖʔδ͔ΒμΠδΣετ
  3. None
  4. None
  5. None
  6. None
  7. None
  8. None
  9. ࠓ೔ͷ΋ͷΑΓॳ৺ऀ޲͚ͳ ͷͰɺͥͻɻ » ࿩Λ໭͠·͢ɻ

  10. #ΦϨΦϨϑϨʔ ϜϫʔΫ ͱ͸ʁ » (ϑϨʔϜϫʔΫ(ҎޙFW)ͷઆ໌ ͸͠·ͤΜ) » ࣗ෼Ͱ࡞ͬͨFW -> ΦϨΦϨFW

    » ݱ୅Ͱ͸ϑϨʔϜϫʔΫ͸ ʮબͿʯ΋ͷ » ੲ͸ϑϨʔϜϫʔΫ͸ͳ͔ͬͨ » ΈΜͳϑϨʔϜϫʔΫΛͭͬ͘ ͨ΋Μ͡Ό…ʢॾઆ͋Γ·͢ʣ
  11. » جຊతʹɺݱ୅Ͱ͸ɺΦϨΦϨ͸ආ͚Δ΂͖ߦҝͱ ͞ΕΔ » ࣗզͷڧ͍FW͸Έͳ͕޾ͤʹͳΕͳ͍͜ͱ͕ଟ ͍

  12. ͦ΋ͦ΋ɺFWͷར఺͕େମͳ͘ͳΔ » ੜ࢈ੑɺ඼࣭ͷ޲্ » ݱ࣮Ͱςετ͞ΕͨϥΠϒϥϦ » ϕλʔϓϥΫςΟεͳख๏ » େن໛։ൃͷجૅ »

    υΩϡϝϯτͷ੔උ » ΤϯδχΞͷֶश » ΤίγεςϜ » ར༻ऀͷϒϩά΍࣭໰αΠτͰͷճ౴ » ϓϥάΠϯͷ๛෋͞
  13. ΦϨΦϨϑϨʔϜϫʔΫͷར఺ʢʁʣ » ͦͷਓ͕͕Μ͹Ε͹ϝϯς͕ଓ͘ » ʢεΩϧͷ͋Δਓ͕ͦΜͳۀ຿ʹ͔·͚͍ͯΔΘ͚ʹ ΋…ʣ » ʮͦͷ࣌ͷʯ(ఆܗ)ۀ຿ʹదͨ͠ઃܭʹͳΔ » ʢ࣌୅͸มΘΓ·͢ͷͰ…Ψϥέʔ޲͚ػೳ͕ࠓ͋ͬͯ

    ΋…ʣ » OSSʹཔΒͳ͍ͰࡁΉ » ʢʮϥΠηϯεͬͯΑ͘Θ͔Βͳ͍ΜͩΑͶʯʮͳΔ΄ Ͳʯʣ
  14. ͳͷʹɺͳͥࣗ࡞ͯ͠͠·͏ͷ͔ʁʁ » ΦϨΦϨϑϨʔϜϫʔΫΛʮ࡞Δʯͱຊਓͷܦݧ஋͸૿͑ Δ » ʢධՁ͞ΕΔ͔͸ผʣ » ൚༻తͳྗͷ޲্ » ຊਓͷ૝૾ྗɾίʔυϦʔσΟϯάͷεΩϧΞοϓ

    » ίϐʔ͢Δͷ΋؆୯Ͱ͸ͳ͍ » ͳʹ͔͏·͍͔͘ͳ͍࣌ɺFWͷίʔυΛಡΊΔ » ʮͳ͔ͥ͜ΕͰ͏͘͝ʯ͕ݮΔ
  15. ʮͪΐͬͱ·ͬͯʂʯ » ͋ͳͨͷʮࠓͷ࢓ࣄʯ͸ΦϨΦϨϑϨʔϜϫʔΫΛ࡞Δ ͜ͱ͔ʁ » ੈքฏ࿨ʹ͸ڵຯ͕ͳ͍ͷ͔ʁ » ࣗ୐ͰӅΕͯͬͦ͜Γ΍Γ·͠ΐ͏ » Ұ౓΋࡞ͬͨ͜ͱແ͍ͷ͸Ͳ͏ͳͷ͔ʁʢ࿝֐ൃݴʣ

    » ؾ߹Λ͍Ε͍͚ͯ͹ɺΦϨΦϨ͔Β௒͍͑ͯ͘͜ͱ ΋…ʂ » ʮͦͷ֮ޛ͸͋Δ͔ʁʯʮͳ͍Θʔʔʯ
  16. » https://twitter.com/excite__pr/status/ 1082482594401288193

  17. ΍͍͖ͬͯ·͠ΐ͏

  18. ॳ৺ऀ޲͚ɺΦϨΦϨ࡞੒ʹ͋ͨͬͯඞཁͳ৺ߏ ͑ » ंྠ FWͷ࠶ൃ໌ʹ͋ͨͬͯͷ৺ߏ͑Λ఻͑·͢

  19. ंྠ͸࠶ൃ໌͢Δ΋ͷ » ਓؾͷंྠ͸།Ұ࠷ߴͷंྠͰ͸ͳ͍ » ͋ͳͨͷυϝΠϯʹϚον͍ͯ͠ͳ͍͔΋ » ࠷ߴ͸৭ʑ༗Δ » ྫɿάϦοϓྗ͕௿ͯ͘΋ɺύϯΫ͠ͳ͍λΠϠ͕͍͍ »

    ྫɿτϥϯΫʹੵΉۓٸ༻͔ͩΒখ͍͞ͷ͕ྑ͍ » ଞਓ͕࠷ߴͱײ͡Δඞཁ͸ͳ͍ » ʮ˓˓ͷFWͷ͜Ε͸࠷ߴʂʯ͸ΦϨΦϨͱ૬൓͠ͳ͍ » श࡞ͳΒʮࣗ෼ͷʯ࠷ߴΛ໨ࢦ͢ͱΑ͍
  20. ंྠ͸ंྠͩ » Ͱ͖Ε͹ૉ௚ʹؙ͘࡞Ζ͏ » ߴػೳͰͳͯ͘΋ɺؙ͚Ε͹ंྠʹ͸ͳΔ » ͨͱ͑͹ɺΑ͋͘ΔϧʔλʔΛ࡞Δ(͚ͭΔ) » ʮͳΜͰଞͷϑϨʔϜϫʔΫ͸͜͏ͳͬͯͳ͍Μͩʁ ԶͳΒ͜͏͢Δʂʯ

  21. » ʮಉ྅ʹ࠘·Εͳ͍ΦϨΦϨ΋͋Δ͸ͣͳΜͩɺͦ ͏ݴͬͯஉ͸εύήοςΟͷ৿ʹফ͑ͨ…ʯ » ͩΕ΋΍͍ͬͯͳ͍ઃܭ͸᠘͔΋ɺ஫ҙʂ

  22. Α͋͘ΔਥೋපɺREST(ful)ฤ » (APIʹ͓͍ͯ͸)REST෩ͳύεύϥϝʔλʹ΋ٙ໰͕͋Δ » /book/1ͱ͔΍Δͱɺཪଆʹbookςʔϒϧͷid1͕ඞਢͱ͔ ͋Γ͕ͪ » ϦιʔεʢDBͷςʔϒϧͱີ݁߹ʣࢤ޲͸ݶք͕͋ΔͷͰ ͸ »

    ʮ_methodͬͯͳΜͩΑϫϩλɺେࣗવʹPATCHͳ͍΍Ζʯ » ʮഁյ͕ͳ͍ͳΒGETʯͷ༥௨ͷ͖͔ͳ͞ » ߴ౓Ͱগͳ͍ίʔυΑΓɺόΧͰ΋Θ͔Δྔͷ͋Δίʔυ ͷ΄͏͕ͳΜͱ͔ͳΓ΍͍͢ʢओ؍ʣ
  23. ઌߦ੡඼Λ͔͍ͭ͜ͳͤ » ͔͍ͭ͜ͳͤͳ͍͍͍Θ͚ͰΦϨΦϨΛͭͬͯ͘͸ͳ Β͵ » (͢ΔͱʮΦϨΦϨ͍Βͳ͍ͳʁʯͱ͍͏ฏ࿨ͳॴʹ ߦ͖ண͘ࣄ΋͋Γ·͢ɻ)

  24. ंྠ͸෦඼ͩ(ओ؍) » ʮಛ஫඼ʯ͸ආ͚Δ΂͖ » ઃܭͷ࣮ફςετෆ଍ » ࠷ߴͷ෦඼͸൚༻෦඼ͩ » ୅ସ͕ޮ͘

  25. » ͨͱ͑͹ϧʔλʔ » ΄ͱΜͲͷ΋ͷ͸IFઃܭ͕ࣅ͍ͯΔ » ʢݱ࣮ੈքͰ࣮ূ͞Εͨ࢖͍΍͢͞ʣ » ަ׵Ͱ͖Δ » ʢAPI͸ۃ୺ʹ͸มΘΒͳ͍ͷͰɺ࡞ͬͯࠩ͠ସ

    ͑΍͍͢ʣ » ࢖͍ํ΋ʹͨΓΑͬͨΓ » ʢֶशίετ͕௿͍ʣ
  26. ৺ߏ͑·ͱΊ » ʮੈؒͷ࠷ߴʯ͸Αͦʹஔ͘ » श࡞͔ͩΒͦ͜ » ʮ͋Ε͕ͳ͍ɺ͜Ε͕ͳ͍ʯ͸ແ༻ » Ͳͷ෦෼ͷந৅౓Λ্͛Δ͔͸ɺҊ݅ʹΑΔ »

    ͱ͸͍͑ɺయܕྫΛ໛฿͢Δͱഁ୼͠ਏ͍ » (ΦϨΦϨͰഁ୼Λؾʹ͢Δͷ͔ʁ)
  27. ॳ৺ऀ޲͚ͷखͷ෇͚ํ » ॳ৺ऀ͸طଘͷϑϨʔϜϫʔΫͰΞϓϦΛ࡞ͬͯΈΔ ͱΑ͍ » ඞཁͳॴ͕ݟ͑ͯ͘Δ » ؾʹ৯Θͳ͍෦෼΋ݟ͑ͯ͘Δʢ͕ࣗ͜͜ݾຬ଍ ͷͨΊʹॏཁʣ »

    ʢ΋͠ຬ଍Ͱ͖Ε͹ؙṶ͚ʣ » ͦΕΛΦϨΦϨFWʹҠ২͠Α͏ʂ
  28. ॱ൪ʹͭͬͯ͘ɺࠩ͠ସ͍͑ͯ͘ » શ෦ΛҰؾʹͭ͘Βͳ͍ͱಈ͔ͳ͍ͱͭΒ͍ » ͪΐͬͱͮͭஔ͖׵͍͑ͯ͘ » (͢ΔͱɺϑϧελοΫͰͳ͘ɺ෦඼୯ҐͷFW͕ Α͍Ͷʁ) » Ͱ΋ɺπΪϋΪͬΆ͘ͳΔΑͶ…ʁ

    » ϑϧελοΫ͸ࣗ৴͕Ͱ͖͔ͯΒ΍Ζ͏
  29. ॳ৺ऀ͕(؆୯͔ͩΒ)࡞Δ΂͖ػೳ » ϧʔλʔ » όϦσʔλʔ » DI෩ίϯςφ » ςϯϓϨʔτΤϯδϯ…ͷϔϧύʔ

  30. Ϥγʂ » ʮLaravelΈ͍ͨͳςϯϓϨʔτΤϯδϯ࡞Ζ͏ʯ » ʮLaravelΈ͍ͨͳDIΛ࡞Ζ͏ʯ » ʮLaravelΈ͍ͨͳORMΛ࡞Ζ͏ʯ » ʮΑ͠ʂ-BSBWFMͷίʔυಡ΋͏ʂʯ

  31. …ʢॳ৺ऀʹ͸ʣແཧͰ͸ʁʁ » ࢖͏ػೳ͕ࣗ෼Ͱͭ͘Εͳ͍ʁ » ΦϨΦϨ͔ͩΒఘΊΔʁ » SUGOIϥΠϒϥϦΛ࢖͏ʁ » ࢓༷ଆΛม͑Δʁ »

    खஈ͸ͳΜͰ΋ΞϦͩΑɺͩͬͯΦϨΦϨͩ΋Μ » (ྫྷ੩ʹͳͬͯ͜͜ͰΦϨΦϨ࡞੒ΛࢭΊΔ((?ʁ
  32. ॳ৺ऀ͕ݟΔ΂͖ϑϨʔϜϫʔΫ » ݹ͍Μ͚ͩͲɺFWͷίʔυΛಡΜͩ͜ͱ͕ͳ͍ͳΒ·ͣ͸͜ͷลΓΛ ಡΉͱྑ͛͞ » ੿࡞ͷOre1,2 » https://github.com/uzulla/Ore » https://github.com/uzulla/Ore2

    » Limonade » Slim Frameworkͷ2.xܥ » phpixieͷ2.xܥ » ͜ΕΒ͸ൺֱతಡΈ΍͍͚ͩ͢Ͱ (Ұൠతʹ͸)࠷ߴͷ'8Ͱ͸ͳ͍ɺ೦಄ʹ͓͘͜ͱ
  33. ଞɺαϯϓϧίʔυͷ୳͠ํ » GitHubΛͱΓ͋͑ͣݕࡧͯ͠ΈΔ » php web frameworkͱ͔Ͱݕࡧ » GHʹ͸੕ͷΑ͏ʹɺຖ೔ΦϨΦϨFW͕ര஀ͯ͠ ͍ΔͷͰ༐ؾ͕༙͘ʂ

    » Ͱ͖Ε͹Star͕ଟͯ͘ɺίʔυ͕ಡΊͦ͏ͳ΋ͷ͕ Α͍ » ͱΓ͋͑ͣ৭ʑಈ͔ͯ͠ΈΔ
  34. Tips » Commit͕গͳ͍΋ͷ͸஍ཕʢͱ͍͏͔׬੒ͯ͠ͳ͍ʣ » υΩϡϝϯτ͕΋ͷ͘͢͝੔උ͞Ε͍ͯΔ΋ͷ͸༻్͕൚༻త͢ ͗Δ͔΋ʢ༷ʑͳέʔεʹରԠ͢ΔͨΊɺෳࡶͩͬͨΓ͢Δʣ » ίϛολʔ͕͘͢͝ଟ͍΋ͷ͸ඍົ » ϓϥάΠϯ͕ͳ͍΋ͷ͕Α͍ʢϓϥάΠϯΛ࣮ݱ͢ΔͨΊʹɺෳ

    ࡶͳ͜ͱ͕ଟ͍ʣ » ʮ͋Εʹ΋͜Εʹ΋ରԠʂʯ͸ʢίʔυ͕୹͘ͱ΋ʂʣந৅౓ ͕ߴ͘ɺֶͼ͸͋Δ͕ෳࡶ » ૉ௚ʹʮ͜Ε͔͠Ͱ͖·ͤΜʂʯͷ΄͏͕౰વ୯७
  35. ͦͯ͠࡞ऀʹܟҙΛ » ଟ͘ͷOSSϥΠηϯε͸ྲྀ༻͕Ͱ͖Δɺ࠷ߴʂ » ͨͩ͠ϥΠηϯεʹ͸ै͏͜ͱ » MITͳΒAuthor౳ΛͲ͔͜ʹࡌͤΔͳͲ » GPL͔Βྲྀ༻͢ΔͳΒɺGPLʹ͢ΔͳͲ »

    ϥΠηϯεهࡌͷͳ͍ϒϩά౳͔Βͷసࡌ͸NG
  36. » ΦϨΦϨͱ͸͍͑FWΛ࡞Δͷ͔ͩΒɺϥΠηϯεʹ ͍ͭͯ͸ֶ΅͏ » ·͋ઈରʹ഑෍͠ͳ͍ͳΒ͍͍͚Ͳɺޙ͔Β୳͢ͷ͸ େม » (ͦͷ΄͏͕ฏ࿨Ͱ͸ʁʁ) » ͱΓ͋͑ͣɺྲྀ༻ͨ͠ίʔυͷҾ༻ݩURL͘Β͍ϝ

    Ϟ͓ͬͯ͜͏
  37. Ͱ͸ॳ৺ऀ͕FW੡࡞࣌ʹॻ͘΂͖ΞϓϦͱ͸ʁ » ͱ͸ʁ » Ұ௨Γͷػೳ͕ඞཁͰ » ͱΔ΂͖ڍಈ͕͸͖ͬΓ͍ͯ͠Δ΋ͷ » (୯७͔ɺ͓खຊ͕͋Δ΋ͷ)

  38. ೖ໳ » URL͕index.phpͰ͓ΘΒͳ͍΋ͷ » GET,POST͕͋Δ΋ͷ » Ϣʔβʔ͕ࣗ༝ͳจࣈΛೖྗͰ͖Δ΋ͷ » ʢϑΥʔϜͷʣ֬ೝը໘͕͋Δ΋ͷ »

    ʢϑΥʔϜͷʣϑΟʔϧυʹ੍໿ʢͨͱ͑͹ϝΞυʣ ͕͋Δ΋ͷ » = ϝʔϧϑΥʔϜʁ
  39. ॳڃ » CSRF TokenΛඋ͑Δ΋ͷ » HTMLҎ֎ɺJSON౳ΛϨεϙϯεͰ͖Δ΋ͷ » ϦμΠϨΫτ͕͋Δ΋ͷ » σʔλϕʔεʹಡΈॻ͖ߋ৽͢Δ࢓૊Έ

    » = ܝࣔ൘ʁ
  40. தڃ » ϩάΠϯʢSessionʣ͕͋Δ΋ͷ » αΠϯΞοϓ͕͋Δ΋ͷ » Delete FlagͰͷ࡟আ » (Del

    flag͕ྑ͍ͱݴ͏͜ͱͰ͸ͳ͍ʣ » ೚ҙͷΧϥϜͰͷ߱ॱɾঢॱιʔτ » N+1తͳɺෳ਺ͷςʔϒϧΛ݁߹͢Δඞཁ͕͋Δ΋ͷ » Ϣʔβʔը໘ͱ෼཭͞Εͨ؅ཧը໘͕͋Δ΋ͷ » = ձһ੍ܝࣔ൘ʁ
  41. ্ڃ » ϑΝΠϧΛΞοϓϩʔυ͢Δ΋ͷ » ʢڊେͳɺϝϞϦ͔ΒᷓΕͦ͏ͳʣϑΝΠϧΛμ΢ϯϩʔ υ͢Δ΋ͷ » ෳ਺ΧϥϜͷΩʔϫʔυݕࡧ » ೚ҙͷෳ਺৚݅Ͱͷݕࡧ

    » ૯݅਺͕දࣔ͞Ε͍ͯΔϖʔδϟʔ » ACL » = (΢ΣϒUIͷ)*OTUBHSBN
  42. ௒্ڃ » SNSΈ͍ͨͳҟৗʹେྔͷRoute΍Model͕͋ΔαΠ τ » ECαΠτΈ͍ͨʹେྔͷϩοΫɾτϥϯβΫγϣ ϯɾ֎෦࿈ܞ͕ඞཁͳαΠτ » ιγϟήΈ͍ͨʹେྔͷΞΫηε͕ͷ͔͔͠ΓɺΠϕ ϯτΈ͍ͨͳେྔͷ୹ظϩδοΫ͕ऻͬͯ͘ΔαΠτ

    » ʢ͜͜·Ͱ͘ΔͱɺٯʹΦϨΦϨϑϨʔϜϫʔΫ͕ ૿͑࢝ΊΔ…ʣ
  43. େମ͜͜Β΁ΜΛ·ͱΊΔͱ » ௒ॳ৺ऀ͸ϩάΠϯͳ͠ͷܝࣔ൘ » தɾ্ڃڃऀ͸Instagram΋Ͳ͖Λ࡞Δͱྑ͍ͱࢥ ͍·͢ » ͋ͳͨ͸FWͳ͠ͰͲ͜·Ͱॻ͚·͔͢ʁ » ॻ͚ͳ͍ʁ͡Ό͋وํʹ͸࣮Γ͕༗ΔνϟϨϯδ

    ʹͳΓͦ͏ʂ
  44. ΦϨΦϨFWͱηΩϡϦςΟʹ͍ͭͯ » ΦϨΦϨ͔ͩΒͱආ͚ͯ௨Δ΂͖Ͱ͸ͳ͍ » ݹ͍FWͰΑ͋ͬͨ͘ϠόΠྫ » ύϥϝʔλΛͦͷ··ม਺ʹల։͢Δͱศརʂ » Ϣʔβʔͷೖྗ͸֬ೝը໘ͰνΣοΫͨ͠͠ɺhiddenΛͦͷ··Ϟ σϧʹ͍ΕΕ͹ศརʂ

    » อଘ͢Δςʔϒϧ໊ΛϢʔβʔೖྗ͔Βϓϧμ΢ϯͰબϕΔ͚Ͳɺϓ ϧμ΢ϯͰબ୒ࢶݻఆ͔ͩΒSQL૊Έཱͯʹ͔ͭ͑͹ศརʂ » URL͔ΒΫϥε΍ϝιου໊ΛҾͬுΕΔͱϧʔλʔෆཁͰศརʂ » ௕ظؒɺߏ଄Խ͞Ε໊ͨલ΍ΞΠίϯ౳ͷϩάΠϯ৘ใ഑ྻΛอଘ͠ ͍͚ͨͲserialize()Ͱจࣈྻʹͯ͠Cookieʹ͍ΕΔͱศརʂ
  45. » ݹ͍ίʔυ͸ ౰࣌͸ΞϦͩͬͨ ϠόΠίʔυ͕͍ͬͺ ͍ɺਅࣅΔͱةݥ » Ͱ΋ɺʮ͜ͷίʔυ͸ةݥʯͱ͔Θ͔Βͳ͍͓… » ݹ͍ઃܭ͚ͩͲόʔδϣϯ͕ͪΌΜͱ্͕͍ͬͯΔ FWΛਅࣅ͠Α͏ʢ͋Δͷ͔ʁʣ

    » ษڧ͠·͠ΐ͏ » ಙؙຊ » աڈͷCVEΛͲΜͲΜಡΉ » (େม͚ͩͲ࣮ྫ͕ͲΜͲΜΘ͔Δ͠ɺલޙͷVerUpΛ ୳Ε͹࣮ࡍͷରࡦίʔυ͕Έ͔ͭΓɺ͓͢͢Ί)
  46. ΍͍͖ͬͯ·͠ΐ͏ » ܝࣔ൘͘Β͍ͳΒɺ๺ւಓͷτʔΫΛݟ͍ͯͩ͘͞ ʢ͕࣌ؒ଍Γ͵ʣ » ʮPHPerਓੜɺҰ౓͸ϑϨʔϜϫʔΫΛ࡞͓ͬͯ͜ ͏ʂʯ » https://speakerdeck.com/uzulla/phperren- sheng-du-hahuremuwakuwozuo-tuteokou

  47. ͱ͍͏͜ͱͰɺ࣮ྫʢʁʣ঺հ » ࠷ԶʹΑΔɺԶͷͨΊͷฏ੒࠷ޙͷΦϨΦϨϑϨʔ ϜϫʔΫͷ͝঺հ͢ΔΑʂʂ » ʢޙͰࢿྉ͸UL͢ΔͷͰɺ੎͍ྑ͘ߦ͖·͢ʣ » ॳ৺ऀ޲͚ͬΆ͘ͳ͍࿩͕ଓ͖·͢ʂ͝ΊΜͳ͍͞ʂ

  48. ܯࠂ » ओ؍͕ଟ͍ » ࢲ͸ࢲͷ՝୊͔͠ߟ͍͑ͯͳ͍ » ͋ͳͨ΋ओ؍Λ΋ͬͯ͑͑Μ΍Ͱʂͱ͍͏͜ͱͰ ͢ » Τϯλϝͱͯ͠ݟ͍ͯͩ͘͞ʂ

  49. ݸਓతͳಈػ » ΊͪΌΊͪΌେख͔ɺϕϯνϟʔΈ͍ͨͳॴͷ࢓ࣄ͕ ଟ͍ » ༧ࢉʹγϏΞɺνʔϜͰͷೳྗࠩ͸ܹ͍͠ » ͔͠͠ଟ͘ͷ৔߹ɺܧଓͯ͠։ൃ͢Δ͜ͱ΋গͳ͍ » ͢͹΍͘ܖ໿ऴྃɾΫϏʹͳΔ

    » ͦͷޙɺεϙοτґཔ͕ଟ͍ » ͔͠͠ɺΞϓϦͷ໋͸݁ߏ௕͍
  50. ਺೥ޙʹ͘Δʮ͜Ε௚ͯ͠ʯ » ফඅ੫͕ɺ೥߸͕͔ΘΓ·ͨ͠ʙ » ݸਓ৘ใอޢ๏͕͔ΘΓ·ͨ͠ʙ » ܾࡁձࣾΛม͑·ͨ͠ʙ » αʔόʔҠసͯ͠PHPόʔδϣϯ୅ΘΓ·ͨ͠ʙ »

    S3ͷೝূ͕ʙ » APIΛ͸΍͍ͨ͠ΜͰ͢ʙ » ޙ೚͕ʹ͛·ͨ͠ʙ » (૬ख΋࢓ํͳ͘΍Β͟ΔΛಘͳ͍मਖ਼΋ଟ͍
  51. ηΩϡϦςΟରԠ » ಥવग़ΔFWͷCVE » ʢ͓٬͕ʣίετΛ෷͑ͳ͍ » ͜Ε͕ʮᘥᙪʯ͔ͰᎍΊΔͭΒ͍ʂ » ʮFWબఆʹΑΔ੹೚ʯ͕໰ΘΕΔ͜ͱ΋

  52. » ηΩϡϦςΟקࠂʹରԠ͢Δࣄ͕ʮηΩϡϦςΟʯͰ ͸ͳ͍…͕…ཁٻͱͯ͠͸ͦ͏ͳΓ͕ͪ » ͳ͓ʮബ͍ϑϨʔϜϫʔΫʯͩͱɺΞϓσͰ͖Δ ࣄ͕ଟ͍͕ͦΕ͸ηΩϡΞͱΠίʔϧͰ͸ͳ͍ » ࢓ํͳ͘ύον΍ϫʔΫΞϥ΢ϯυΛೖΕΔ » ϑϨʔϜϫʔΫʹϫʔΫΞϥ΢ϯυΛೖΕΔͱߦ

    ͖ࢭ·Γ » Ϗδωεʹ͓͍ͯ͜ͷίετΛʮݟࠐΉʯ͔ɺʮආ͚ Δʯඞཁ͕͋Δɻ
  53. ྑ͍ϑϨʔϜϫʔΫͰղܾ͠ͳ͍ʂ » ςετͱɺςετ͕ݱ࣮తʹͰ͖Δਖ਼ؾͳઃܭ͕ॏཁ » FWͰϨʔϧ͔ΒམͪΔͷ͸؆୯ » ʮύϫʔϓϨΠʯͰʮҟৗͳཁ݅ʢओ؍ʣʯ͕͸͍Δ ͱɺͲΜͳϑϨʔϜϫʔΫͰ΋ऴΘΓ » ʮϥϐουʹߦ͚ΔʯFW΋ɺݱ৔ͰϥϐουΛڧ੍

    ͞Ε͚ͭͮΔͱૣ൩ϥϐουʹ͍͚ͳ͘ͳΓ͕ͪ
  54. ࡢࠓͷଟ༷ͳ؀ڥ΁ͷରԠ » όον΍ɺLambdaɺSwooleɾReactPHPΈ͍ͨͳมΘ࣮ͬͨߦ ؀ڥ » άάΔͱͰͯ͘Δɺී௨ͷFWͱͭͳ͙ʮΞμϓλʯͱ͍͏΍ͭ ͸ » ORM΍ίϯϑΟάɺDI͕࿩Λ΍΍͕ͪ͘͜͠͠ »

    ʮFW͔Β੾Γग़ͤ·͢Αʈʈʯʮ৴͡ͳ͍Αʂʯ » ʮ͏·͚͍ͤͬ͘͢Ε͹͍ͩ͡ΐ͏Ϳʯ͚ͩͲFWͷҙຯ͕ബ ͘ͳΔ » POPOʢPlain old PHP ObjectʣͩͱେମͲ͜ʹͰ΋͍͚࣋ͬͯΔ
  55. ݸਓతͳ೰Έ·ͱΊ » ʮ̍Օॴ͔͑Ε͹ɺશ෦มΘΔʯΑ͘Ͱ͖ͨ'8͸࠷ ߴ » ͔͠͠ɺ೥୯ҐͰ͸όʔδϣϯΞοϓ͕ඞཁʢओ ؍ʣ » εϙοτ࡞ۀ͹͔ΓͰʮܧଓ͠ ͓͕ͯۚ΋Β͑

    ͳ ͍ʯҊ݅Ͱ์ஔ͞ΕΔͱ٧Ή » ʮయܕతͳFWʯʹ൓߅͍͓ͨ͠೥ࠒʂ
  56. » (Ұ෦ͷҊ݅Ͱ)FW΁ͷఘΊ » ڋ൱͍ͨ͠Θ͚Ͱ͸ͳ͍͕ɺൣғΛݮΒ͔͢ʁ » ͔ͦ͠͠ΕͰ͸FWͷҙ͕ٛ… » …Α͠ɺΦϨΦϨ͔ͳʂʢ࿦ཧͷඈ༂ʣ » (͜Ε͸ੈͷதͷΦϨΦϨFWͭ͘Δਓؒͷయܕత

    ͳݴ͍༁Ͱ͢ɻಉ྅͕͜͏͍͏͜ͱΛݴ͍ग़ͨ͠ ΒԥͬͯࢭΊ·͠ΐ͏) » (ಉ྅Ͱͳ͍ͳΒ(ྫ͑͹๻͕ݴ͍ग़ͨ͠Β)ɺͦͬ ͱ۪ஒΛฉ͍͍ͯ͋͛ͯͩ͘͞)
  57. Α͠… » ʮ̍Օॴม͑Ε͹શ෦มΘΔʯ » ʮߴ͍ੜ࢈ੑʯ » ʮݟ௨͠ͷྑ͍ίʔυʯ » Λ࣮ݱ͢Δૉఢͳຐ๏Λࣺͯͯ… »

    ෺ཧͰΰϦԡ͠Ͱઓ͏ͧʂʂʂ
  58. ͱ͍͏͜ͱͰΦϨΦϨϑϨʔϜϫʔΫΛ࡞Δͧʂ » ͋͘·Ͱ΋ݸਓతͳײ૝Ͱɺօ༷͸ͦ͏Ͱ͸ͳ͍͔ ΋͠Εͳ͍ɻ » ʢτʔΫͷྲྀΕ্ɺ͜͜͸ೲಘ͍ͩ͘͞ʣ » ʮͳΜͰ͋ΕɺΦϨΦϨ͸ͳ͍ͩΖʯͱ͍͏ͷ͸ਖ਼ ؾͳҙݟͰ͢ʢࢲ΋ී௨ʹී௨ͷϑϨʔϜϫʔΫ΋ ࢖͍·͢ʣ

    ͥͻͦͷ··͓͍࣋ͪͩ͘͞
  59. Ore3 FW » https://github.com/uzulla/Ore3 » (Ore1,2͸લ࡞ͬͨͷͰ(҆қ)) » ༻్ɺJSON API »

    ໨ࢦ͢ॴ » ΤϥʔϋϯυϦϯά » ୯७͞ » αόΠϒੑʢओ؍ » ςετ͠΍͢͞
  60. ʮαόΠϒʯͱ͸ʁ » Ͱ͖Ε͹ɺ<৽ݩ߸>5೥Ͱ΋ɺͪΐͬͱͷमਖ਼Ͱಈ͘ » ՄೳͳΒɺฏ੒ͷϥΠϒϥϦΛࢥ͍ग़͞ͳͯ͘ࡁΉ » ئΘ͘͹ɺ͔ͦ͜Βյͣ͞ʹमਖ਼Ͱ͖Δ » ख͕͔͔ؒͬͯ΋ɺ95%ͷέʔεͰ޻਺͕ಡΈ΍͢ ͍ɺϋϚΒͳ͍

    » ։ൃதͷ࢓༷ύϫʔϓϨΠʹରԠͰ͖Δ
  61. ࠓճͷΦϨΦϨFWʹ͓͚Δࡦ » ʮίʔυͷ֎ʯʹཔΔ͕ɺੜ੒͸͠ͳ͍ » *%&ͳͲπʔϧͷαϙʔτʢิ׬ɺ੩తղੳɺϦϑΝΫλػೳʣ Λ࠷େݶʹड͚ΒΕΔΑ͏ʹ » ੩తղੳ(ྫ:IDEͷInspect Code)ͷ׆༻ »

    ૉ๿ͳςετͷίετΛԼ͛Δ » ๨Εͯ΋͓͍͔͚ΒΕΔΑ͏ʹ » ҉໧ͷίʔυΛ΁Β͢(഑ྻΛҾ͖ճ͞ͳ͍ɺΫϥε΍ϓϩύςΟ Λ࡞Δ) » VCSͱͷ਌࿨ੑΛ্͛Δ(#MBNF͠΍͘͢ɺ%J⒎ΛΈ΍͘͢ ओ؍ )
  62. ʮٯʹIDE౳ͷπʔϧͷຐ๏ʹཔͬͯͳ͍͔ʁʯ » ࠓޙIDEʢ΍PHPͷ੍໿ʣ͕؇Ήํ޲ʹਐ·ͳ͍ࣄʹ ౌ͚͍ͯΔ » ʮ…͜ΕPHPUnit͔ͭͬͯΔΑͶʁʯʮ΢οʯ

  63. ࠓճ࡞ͬͨػೳ » ϧʔλʔ » Ϗϡʔ » ORM » DI

  64. ࠓճ࡞ͬͨػೳʂ » ϧʔλʔ ͳ͠ ! » Ϗϡʔ ͳ͠ ! »

    ORM ͳ͠ ! » DI ͳ͠ !
  65. ࣮૷ͨ͠ػೳ͸ » ϦΫΤετ/Ϩεϙϯε ΦϒδΣΫτ » େҬͳΤϥʔϋϯυϦϯά

  66. ͓࡞๏(ػೳͰ͸ͳ͍) » ϦΫΤετɺϨεϙϯεͷ࡞๏ » σʔλɾϞσϧपΓͷ͓࡞๏

  67. ϑΝΠϧߏ଄ !"" composer.json !"" api_real.php !"" shell.php !"" lib #

    $"" MyApp # !"" Api # # !"" Action # # !"" Request # # $"" Response # !"" Model # !"" Repo # $"" Service $"" tests # $"" testTest.php $"" vendor
  68. !"" composer.json !"" api_real.php !" !"" shell.php !"" lib #

    $"" MyApp # !"" Api # # !"" Action # # !"" Request # # $"" Response # !"" Model # !"" Repo # $"" Service $"" tests # $"" testTest.php $"" vendor
  69. api_realͷྲྀΕ » 0. Τϥʔϋϯυϥొ࿥ » 1. σΟεύον » 2. ϦΫΤετΦϒδΣΫτੜ੒(*Request.php)

    » 3. ΞΫγϣϯ࣮ߦ(*Action.php) » 4. (ΞΫγϣϯͷதͰ)ϨεϙϯεΦϒδΣΫτੜ ੒(*Response.php) » 5. ϨεϙϯεΦϒδΣΫτΛૹ৴
  70. ୯७Խͨ͠΋ͷ set_error_handler(/* ... */); // 0. Τϥʔϋϯυϥ try{ if($_SERVER['REQUEST_URI']='/'){ //

    1. σΟεύν $req = new SomeRequest($_POST); // 2. reqੜ੒ $res = SomeAction::run($req); // 3. resੜ੒ }else{ /* ... */ } } // $res 4. Ϩεϙϯε $res->writeHeader($http_origin_header); // 5. ૹ৴ $res->writeBody();// 5. ૹ৴
  71. 0. Τϥʔϋϯυϥઃఆ౳-1 (গʑ؆ུԽͯ͠·͢ set_error_handler(function ($severity, $message, $file, $line) { throw

    new ErrorException($message, 0, $severity, $file, $line); }); register_shutdown_function(function () { $error = error_get_last(); if (!is_array($error) || !($error['type'] & (E_ERROR|E_PARSE|E_USER_ERROR|E_RECOVERABLE_ERROR))) { return; } // ਖ਼ৗऴྃܥ error_log("Uncaught Error: ..."); // Ωϟονͨ͠ΤϥʔΛϩά http_response_code(500); // response error header("Content-type: application/json"); echo json_encode([ "code" => 500, "message" => "internal server error" ]); }); // ࣍ͷεϥΠυʹଓ͘
  72. 0. Τϥʔϋϯυϥઃఆ౳-2 (গʑ؆ུԽͯ͠·͢ try { //લͷεϥΠυ͔Βଓ͘ ob_start(); require(__DIR__ . "/vendor/autoload.php");

    // ========= ‼ ͜͜ʹΞϓϦίʔυ ‼ ============= ob_end_flush(); } catch (\Throwable $e) { // Uncaught Exception $error_class_name = get_class($e); error_log("Uncaught Exception {$error_class_name}: ..."); // ྫ֎Λϩά http_response_code(500); // response error header("Content-type: application/json"); echo json_encode([ "code" => 500, "message" => "internal server error" ]); }
  73. » ϋϯυϥΛ࠷ॳʹઃఆ͠ɺNotice΋Warning΋ Ωϟονͯ͠ϩάˍΤϥʔը໘ » ΞϓϦશମ΋tryͰ͘͘ΓɺΩϟονͯ͠ϩάˍΤ ϥʔը໘ » ͜Ε͘Β͍΍Δͱศར » ͜ΕΛઆ໌͢Δͱ௕͘ͳΓ͗͢Δ…ͷͰলུ

    » ʢͦͷ͏ͪͲ͔͜Ͱ͜ͷ࿩͸͍ͨ͠Ͱ͢Ͷʣ
  74. Output bufferͰ༧ظͤ͵ग़ྗΛ཈੍ ob_start();// Output bufferingΛ։࢝ $res = MyApp(); // ͜͜Ͱ͸ͳʹ΋ग़ྗ͠ͳ͍ɺ͋ͬͨΒΤϥʔ͔Կ͔

    $something = ob_get_contents(); // ҙਤ͠ͳ͍ग़ྗ͕͋ͬͨΒϩά΁ if (strlen($something) > 0) { error_log($something); } ob_end_clean(); // (্Ͱϩάʹग़͍ͯ͠ΔͷͰɺࣺͯΔ) ob_start(); // ͔͜͜Β࣮ࡍʹૹ৴ $res->writeHeader($http_origin_header); $res->writeBody(); ob_end_flush();
  75. » obଟ༻ͷ໨త͸ » ʮΤϥʔ࣌ʹ่Εͨग़ྗΛͩ͞ͳ͍͜ͱʯ » ʮ૝ఆ͍ͯ͠ͳ͍ग़ྗΛޡͬͯग़͞ͳ͍͜ͱʯ » ʮޡͬͯ200Λฦ͞ͳ͍͜ͱʯ » PHP͸ɺΤϥʔ౳Ͱ༧ظͤ͵ग़ྗ͕ग़Δͱૹ৴͞Εͯ͠·

    ͏ɺ͢Δͱϔομʔ΋ૹΕͳ͍ɺ͜Ε͸Web APIͩͱඍົ » ͳͷͰɺϨεϙϯεΦϒδΣΫτͰͷૹ৴Ҏ֎͸ɺશ෦ྫ ֎తͳ΋ͷͱͯ͠obͰ֬อͯ͠ϩάߦ͖ʹ͢Δɻ » var_dump()͕print debugͰ࢖͑Δͧʂศརʂ
  76. ࠶ܝࡌʣ୯७Խͨ͠΋ͷ set_error_handler(/* ... */); try{ if($_SERVER['REQUEST_URI']='/'){ $req = new SomeRequest($_POST);

    $res = SomeAction::run($re }else{ /* ... */ } } $res->writeHeader($http_origin_header); $res->writeBody();
  77. 1. σΟεύονͱ͍͏໊લͷifจ $request_uri = $_SERVER['REQUEST_URI']; $method = $_SERVER['REQUEST_METHOD']; $http_origin_header =

    $_SERVER["HTTP_ORIGIN"] ?? null; $base_uri = "/api"; $path = substr($request_uri, strlen($base_uri)); $path = explode("?", $path, 2)[0]; if ($method === "OPTIONS" && !is_null($http_origin_header)) { $res = new \MyApp\Api\Response\CORSPreFlightResponse(); } else if ($method === "GET" && $path === "/hello") { $req = new \MyApp\Api\Request\HelloRequest($_GET); $res = \MyApp\Api\Action\HelloAction::run($req); } else { $res = new \MyApp\Api\Response\Response(); $res->code = 404; }
  78. » ʮ̎̌೥લ͔ͳʁʯ ʮύεύϥϝʔλΛ࢖Θͳ͚Ε͹͑͑Μ΍ʯ » ʢRESTfulͷ͜ͱΛߟ͍͑ͯͳ͍ʣ » ඞཁʹͳΕ͹ϧʔλʔΛೖΕΕ͹͍͍Ͱ͠ΐ » ʮpreg_matchͰ΋࣮ݱͰ͖ΔͰ͠ΐʢʁʁʯ »

    ྑ͍ϧʔλʔΛ͍Εͯ΋ɺେ఍ଟػೳΛ࢖Θͳ͍… » ελοΫτϨʔε͕ബ͍ʢϩά͕ݟ΍͍͢ʣ » ಥવݱΕͨ୹ظతͳṖ࢓༷ͷ૬ख͕Ͱ͖ΔɺϦΫΤε τΛ٧Ίସ͑ͯ͠ΞΫγϣϯΛίʔϧ͢Δͱ͔
  79. ࠶ܝࡌʣ୯७Խͨ͠΋ͷ set_error_handler(/* ... */); // 0. Τϥʔϋϯυϥ try{ if($_SERVER['REQUEST_URI']='/'){ //

    1. σΟεύν $req = new SomeRequest($_POST); // $res = SomeAction::run($req); // 3. resੜ੒ }else{ /* ... */ } } // $res 4. Ϩεϙϯε $res->writeHeader($http_origin_header); // 5. ૹ৴ $res->writeBody();// 5. ૹ৴
  80. !"" composer.json !"" api_real.php !"" shell.php !"" lib # $""

    MyApp # !"" Api # # !"" Action # # !"" Request !" # # $"" Response # !"" Model # !"" Repo # $"" Service $"" tests # $"" testTest.php $"" vendor
  81. 2. ϦΫΤετΦϒδΣΫτ class HelloRequest extends Request implements RequestInterface { use

    ValidateRegexTrait; public $name; public function __construct(array $list) { $el = []; $result = $this->validateWithRegex($el, $list, 'name', "/\A[a-zA-Z0-9]{1,32}\z/u", true); $el = $result->error_list; $this->name = $result->val; $this->_error_list = $el; } }
  82. » جຊ1ϧʔτʹ͖ͭɺ1Ϋϥε » ίϯετϥΫλʹ഑ྻ($_POST,$_COOKIE౳ʣΛ౉͢ » εʔύʔάϩʔόϧ͸ɺ͜ͷޙ͸Ұ੾࢖Θ͵੤͍ » ςετ࣌ʹָˍͦΕ͕ͳ͍ಛघ؀ڥͱͭͳ͗΍͘͢ » Ϋϥε͸༧ఆ͞ΕΔύϥϝλ෼ͷϓϩύςΟม਺Λ࣋ͭ

    » ϗϫΠτϦετͰ໌ࣔత » ޙड़ͷΞΫγϣϯ͸ɺϓϩύςΟม਺Λ௚઀৮Δ » *%&Ͱิ׬ɾ*OTQFDU͠΍͍͢ » ΧϓηϧԽ͕໨తͰ͸ͳ͍ͷͰpublic » ̍ʙׂ̎Ͱ࢖ΘΕΔϝιου͸ɺܧঝͰͳ͘Trait
  83. !"" composer.json !"" api_real.php !"" shell.php !"" lib # $""

    MyApp # !"" Api # # !"" Action !" # # !"" Request # # $"" Response # !"" Model # !"" Repo # $"" Service $"" tests # $"" testTest.php $"" vendor
  84. 3. ΞΫγϣϯ class HelloAction { public static function run(HelloRequest $req):

    ResponseInterface { if (!$req->isValid()) { return new ErrorResponse($req, 400, "bad request", $req->getErrorList()); } $name_san = NameSanService::getByName($req->name); return new HelloSuccessResponse($name_san); } }
  85. » ͍ΘΏΔίϯτϩʔϥʔɺ੩తͳϝιουͰΑ͍ » Ҿ਺͸ϦΫΤετΦϒδΣΫτ » ฦΓ஋͸ResponseInterfaceΛ࣮૷ͨ͠΋ͷ » ޙड़ͷServiceΛୟ͖·͘ΓɺϨεϙϯεΛ࡞Δ

  86. ࠶ܝࡌʣ୯७Խͨ͠΋ͷ set_error_handler(/* ... */); try{ if($_SERVER['REQUEST_URI']='/'){ $req = new SomeRequest($_POST);

    $res = SomeAction::run($req); // ͜͜·ͰऴΘͬͨ }else{ /* ... */ } } // $res 4. Ϩεϙϯε ! $res->writeHeader($http_origin_header); // 5. ૹ৴ $res->writeBody();// 5. ૹ৴
  87. !"" composer.json !"" api_real.php !"" shell.php !"" lib # $""

    MyApp # !"" Api # # !"" Action # # !"" Request # # $"" Response !" # !"" Model # !"" Repo # $"" Service $"" tests # $"" testTest.php $"" vendor
  88. 4. Ϩεϙϯε class HelloSuccessResponse extends Response implements ResponseInterface { public

    $code = 200; public $name_san = null; public function __construct(NameSan $name_san) { $this->code = 200; $this->name_san = $name_san; } public function getBody(): string { return json_encode([ 'code' => $this->code, 'name_with_san' => $this->name_san->name ]); } public function writeBody(): void { echo $this->getBody(); } }
  89. » ϨεϙϯεΦϒδΣΫτ΋ɺίϯετϥΫλͰʮ࣮ࡍʹඞཁͳ Ҿ਺ʯΛड͚औΔ » ͜͜Ͱ͸εΧϥʔͰ͸ͳ͘ɺϞσϧͷΫϥε໊ͰܕΛࢦఆ͢Δ » ϓϩύςΟʢ͜͜Ͱ͸$name_san)ʹ͸ϞσϧͷΠϯελϯε ΛೖΕ͓ͯ͘ » ֤छϞσϧΛϨεϙϯε·Ͱ࣋ͪࠐΉ͓࡞๏ͩͱɺtoArray

    લ͕ݟΕΔͷͰJSONΛ૬खʹจࣈྻςετͤͣʹࡁΉ » मਖ਼ൣғ͕ڱ͍ͷͰɺίϛοτϩά͔Β௥͍͔͚΍͍͢ ʢओ؍ʣ » ͜ͷ""ͱ͍͏ۭจࣈྻ్͕தͷΩϟετϛε͔ɺͦ͏Ͱͳ ͍͔൑அ͠΍͍͢ɺ౳ɻ
  90. » get/writeBody()Ͱॴఆͷܗʹม׵͢ΔͷΛखͰॻ͘ » Ϩεϙϯεͷܗ͸Ϟσϧͷߏ଄ʹґଘͤ͞ͳ͍ » (ఆܗͷdefinitionͷ৔߹ʔͨͱ͑͹UserInfoͱ͔ʔ͸Ͳ͔͜ʹ toArray()ͱ͔ϔϧύΛ࡞Δࣄ΋͋Δ) » ӡ༻ϑΣʔζʹ͸͍Δͱɺςʔϒϧ͸ม͑ͳ͍͚Ͳݟͤํ͸͔ΘΓ͕ͪ »

    ಥવඇਖ਼نͳΧϥϜ͕૿͑Δ࣌ʹɺϞσϧ΍ActionΛ͍͡Βͳͯ͘ ΋ResͰٵऩͰ͖Δ » ྫɿ͋ΔAPI͚ͩauthor͕CSVͰ΄͍͠ʢ΄͔͸഑ྻͳͷʹ…ʣ » ྫɿ͜ͷϨεϙϯε͸Ձ֨ΛӅ͍ͨ͠ɺΫϩʔϧ͞Εͨ͘ͳ͍ » ʮ͜ͷ࢓༷Ͱ߹ҙ͕ͱΕͨΜͩɺ͔ͩΒே·Ͱʹ࡞ͬͯʯ » ͋Δ͍͸ɺϞσϧ͕͔Θͬͯ΋API࢓༷ΛഁյͰ͖ͳ͍
  91. » ͜ͷΫϥεʹૹ৴ʢechoʣ͢Δίʔυ͕͋Δ » body͕ڊେͳόΠφϦͳΒɺ͜͜ͰҰ୴obΛ͸ͣ͢ ͳͲ޻෉͕Ͱ͖Δ » ͦͷͨΊɺʮඞཁʹԠͯ͡ʯResʹStream΍ GeneratorΛΘͨͯ͠Α͍

  92. 4. Ϩεϙϯε(ϔομʔؔ࿈) ؆ུԽͯ͠·͢ class Response implements ResponseInterface { public $code;

    protected $header_list = [ "Content-type" => "application/json" ]; protected $cookie_list = []; public function __construct($code, $name){ $this->code = $code; } public function writeHeader(string $http_origin = null): void { foreach ($this->getHeader($http_origin) as $key => $val) { header(sprintf("%s: %s", $key, $val)); // ϔομૹ৴ } foreach ($this->cookie_list as $cookie) { CookieService::setCookie($cookie); // ΫοΩʔૹ৴ } http_response_code($this->code); // Ϩεϙϯείʔυηοτ /* ... */
  93. » ϔομʔ΍ΫοΩʔ͸ಉ༷ʹϓϩύςΟʹʢ഑ྻͱ͠ ͯʣ΋ͭɻ » cookieͳΜ͔͸CookieͷϞσϧͰ͸͍͍ͬͯΔ » ςετͷͨΊʹ » ࣮ࡍʹwriteHeader͢Δ·Ͱ͸ૹ৴͠ͳ͍ »

    writeBodyಉ༷ʹɺ௚઀ϔομʔΛૹ৴͢Δίʔυ Λ͜͜ʹॻ͘ » Etag΍TTLͱ͔ɺPrivateɺno-cacheΈ͍ͨͳͷ΋ ॻ͘
  94. 5. api_realʹ΋Ͳͬͯૹ৴ set_error_handler(/* ... */); try{ if($_SERVER['REQUEST_URI']='/'){ $req = new

    SomeRequest($_POST); $res = SomeAction::run($req); }else{ /* ... */ } } $res->writeHeader($http_origin_header); // 5. ૹ৴ $res->writeBody();// 5. ૹ৴
  95. » ࠷ޙͰResͷwriteHeader/Body͕ݺ͹ΕΔ » writeHeader()Ͱϔομʔ(CORSܥ΍Content- typeɺExpire΍Attachment)/ΫοΩʔΛૹ৴ » writeBody()͕σʔλΛૹ৴ʢechoʣ » ʢgetBody/Header()͸جຊతʹ͸ςετͷͨΊʹ͋ ΓɺwriteBody()͔ΒgetBody()΁ͷݺͼग़ؔ͠܎͸

    ڧ੍͠ͳ͍ɺͪΐͬͱ໊෇͚͕ඍົ…ʣ
  96. ͸͍ » ܕ͕ଟ͍ » ໌ࣔ » %*Λ࢖Θͳ͍

  97. ͭΒ͍ͱ͜Ζʢଞਓͷ૝૾ʣ » ίʔυ͕ଟ͍ » IDEͱͰ͔͍Ϟχλʔਪ঑ » मਖ਼Օॴ͕ଟ͍ » ҰൃͰόʔϯʂͬͯͳΒͳ͍ »

    IDE͔ͭͬͯͳ͍ͱॻ͖ଛ͕͡ଟ͍ » ϦϑΝΫλ΋IDE͕ͳ͍ͱͭΒ͍ » ແ৺Ͱॻ͖׵͑ΔࠜੑϓϨΠ
  98. ଓ͍ͯɺσʔλपΓͷن໿ະ ຬɺ͓໿ଋ…͸ࠓճεΩοϓ » σʔλͷߏ଄…ͳΜͰ͕͢ » ͞Βʹॳ৺ऀͷܕ…͍΍ํΛஔ͖ڈΓʹ͢Δಠળ తɾಠΓΑ͕Γͳ಺༰ » 30෼ͷτʔΫͰ͸͓ΘΒΜͷͰεΩοϓ͠·͢ʂ ʢ͓ΘΓʹ͚͓͖ͭͯ·͢ʣ

    » ޙͰΈͳ͞ΜࢿྉΛΑΜͰͶʂ
  99. ͸͍

  100. Ore3 ·ͱΊ » ੩తղੳπʔϧ͔ΒཧղͰ͖ΔΑ͏ʹ » ܕΛՄೳͳݶΓॻ͘ » DIͳ͠ » ʮઃఆϑΝΠϧʯ͸࠷খݶʹ

    » ςετͷखؒΛ΁Β͢ » ೖྗͱग़ྗͷςετΛॻ͖΍͘͢ʢओ؍ʣ » PHPຊମͷػೳ͸ૉ௚ʹ͔ͭ͏
  101. » ܽ఺͸΋ͪΖΜमਖ਼ൣғ͕޿͘ͳΔ͜ͱ » IDEͱςετͰࠜੑͰ۪௚ʹ࣏͢ » ςετ΍ܕͰɺ੔߹ੑΛ୲อ͍ͯ͘͠ » ʮ͜ΕFWͷҙຯ͋Δʁʯ » ͔͠͠मਖ਼࣌ؒΛݟੵ΋Γ͠΍͍͢ʢओ؍ʣ

    » 90%ͷཁ݅Λ̍࣌ؒͰ௚ͤΔ୅ΘΓʹ10%Ͱ͸ϋϚͬͯҰि ͔͔ؒΔΑΓɺ95%͕̍ప໷ͰऴΘͬͯ΄͍͠ʢओ؍ʣ » ಥવJOINͱ͔UNIONඞཁʹͳΔͱORMΉ͔ͣ͗ͯ͢͠ ʮSQL͔͔ͤͯ͘ΕʂʂʯͱͳΔʢษڧෆ଍ʣ » ORMͷΉ͔͍ͣ͠࢖͍ํ͸๨Ε͕ͪɺSQLͩͱ͙͢ʹΘ͔ Δ…ʢ࿝ਓʣ
  102. » ʮδϟόͰ͍͍ͷͰ͸ʁʯʮsorry, I am PHPerʯ » ʮhackͰ͍͍ͷͰ͸ʁʯʮhackʹPHPStorm΄͠ ͍ʯ » Typed

    Properties͖ͯ΄͍͠ʂࠓ͙͢ʂ » Enum͖ͯ΄͍͠ʂࠓ͙͢ʂ » listड͚͍ͨ͠ʂδΣωϦΫεʂ » (େମ͜͏͍͏ͷHackʹ͋ΔΜͩΑͳΝ) » ·͋ɺࢲ͸PHPerͳͷͰ
  103. » ͍ͩͿʮࣗݾத৺తʯͰ͢ͶɺΦϨΦϨײ͋Δʂʂ

  104. ݁ՌɺͲ͏ͳ͔ͬͨʁʢϑΟ ΫγϣϯͰ͢ » ʮࢲ͸ʯ޻਺͕ΑΊΔΑ͏ʹͳͬͨ(ओ؍) » IDE͕͋Ε͹ɺ(ςετ͢Δ·Ͱ΋ͳ͘)suspectsͰׂ ͷϛεʹؾ͚ͮΔΑ͏ʹ » (IDE΍ςετΛ͠ͳ͍ਓͱ΍Δͱ)ίʔυमਖ਼ɾϨ Ϗϡʔෛՙ্ঢ

    » ·͋ɺࢲ͕੹೚ͱΔʢ؃औΔʣҊ݅ͳͷͰେৎ෉(?)
  105. ٘ਜ਼͸ͳʹ͔ʁ » ଞਓ͔Βݟͨʮ͓͠ΌΕʯ͞ » ʢΧʔΰɾΧϧτΛ৴͡Δʣࣗ෼ͷࣾձੑ » ̍ՕॴΛม͑Δͱશ෦͕׬੒͢ΔΑ͏ͳମݧ » ػցʢIDEʣʹͨΑΒͳ͚Ε͹ಡΊͳ͍ »

    ػցʢςετʣʹͨΑΒͳ͚Ε͹݈શ͔Θ͔Βͳ͍
  106. ͸͍

  107. ͜Ε͸FWͳͷ͔ʁ » ͜Μͳػೳ͕͘͢ͳ͍͍ͯ͘ͷ͔ʁ » ͍΍͍΍ɺࢲʹ͸͜Ε͸FWͰ͢Α » ίʔυͷଟՉ͕FW͔Ͳ͏͔Ͱ͸ͳ͍ʢ̍πΠʔτ ʹೖΔFWͳͲ͋ΔΘ͚Ͱʣ » FWͱ͸ίʔυͷ࣮ମͰ͸ͳ͍ʂελΠϧͰ͋

    Δʂʢओ؍
  108. ͱ͍͏͜ͱͰΦϨΦϨFWͷ ঺հͰͨ͠ʂ » ੈքͷย۱ʹ͸͜͏͍͏ߟ͑ํ΋͋Δʂ

  109. ॳ৺ऀ޲͚·ͱΊ » FW࡞Δͷ͸ͨͷ͍͠ʂͰ΋ͦͷखؒͰΞϓϦ͕࡞ΕΔ ͧʂʂʂ » ࡞Δ΋ͷ͕ʰੈͷதͷ80%ͷ΢ΣϒΞϓϦʱͳΒɺͨ͠ ͔ʹʰ80%ʹ޲͍͍ͯΔϑϨʔϜϫʔΫʱΛ࢖͏΂͖ » ΦϨΦϨ͸ࣗ෼ࣗ৴΍<৽ݩ߸>ʹjoinͨ͠νʔϜϝΠ τʹ࠘·ΕΔͧʂʂ

    » झຯͷൣғʹ͠·͠ΐ͏ » ʮ࢖͍ํʯҎ֎΋ֶ΅͏
  110. தڃऀ޲͚·ͱΊ » ͝ଘ஌ͷ௨Γ(?)ʮϝδϟʔͳFWΛ͔ͭͬͨΒສࣄղܾʯ͠ͳ͍͕ɺ ਏͯ͘΋͕Μ͹Δͷ͕ਖ਼͍͠ಓͩ » ͢Ͱʹ͋Δ஌ݟɾઃܭɾϥΠϒϥϦΛ୳͠ɺֶ΅͏ » ͨͩɺڝ߹ͱಉ͡Ͱڝ૪ͰউͯΔͷ͔ʁ » FWΛʮ৐Γ׵͑Δʯͱ͍͏ߦҝࣗମ͕͔ͳΓܦݧ͕ͨ·ΔͷͰἚͷ

    ಓΛΏ͜͏ » ΦϨΦϨFW͔Β୤٫Ͱ͖Δɺ͋Δ͍͸ΦϨΦϨFWʹҠߦͰ͖Δ ઃܭ » ʮࠓͲ͖͸͜Εͩʂʯͱ͔ࣖ೥૿ʹͳΔͱɺPHPerϥΠϑͷָ͠͞ ͕൒ݮͯ͠͠·͏ͧʂΈΜͳΦϨΦϨͯ͠Δʂ܅΋ΦϨΦϨ͠Α͏ʂ
  111. ্ڃऀ޲͚·ͱΊ » ʮ͜Μͳ͜ͱ͍ͬͯΔ͚ͲΦϨΦϨ͕̑೥͔࣋ͭʁʯ ʮͦΕͳʯ » ୤ग़͸ݟࠐΜͰ͓͔͘͠ͳ͍͠ɺͦͷͨΊʹ͸ۃྗ ෼཭Մೳʹ͠ɺγϯϓϧʹ͍͖͍ͯͨ͠ » Ҡॅ͕Ͱ͖ΔͳΒɺͲΜͳFWͰ΋ɺΦϨΦϨͰ΋͓ ͦΔΔʹ଍Βͣʢͦ͏͔ʁʁʣ

    » ࢲ৴ɿΠέͯΔSQLBuilderΛ͕͚͍ͭͮͯ͞͠·͢
  112. ·ͱΊ » ʮϚδϣϦςΟʢʁʣʯΛ໡৴ͯ͠·ͤΜ͔ʁ » ׳ྫΛٙ͏ͷ͸ॏཁ » ʢതଧͱͯ͠͸ɺϚδϣϦςΟͷํ͕҆ṛ͚ͩͲʂʣ » ʮ͍͍͜ͱݴͬͯΔʯ෩ͳҙݟΛ৴͡Δͳʢʁʁʁ »

    #΍ͬͯΈΑ͏ͥ » ͱ͍͏͜ͱͰɺΈΜͳ ࣗ͝୐Ͱ ΦϨΦϨϑϨʔϜϫʔ ΫΛ͍ͭͬͯ͘͜͏ͳʂʂΦϨʹ΋Έͤͯ͘Εʂʂ
  113. ׬

  114. ܁Γฦ͠ » #ΦϨΦϨϑϨʔϜϫʔΫ ͸·ͣ͸झຯͰ΍Ζ͏ͳʂʂ

  115. ʮͳͥPSR-7(౳)Ͱ͸ͳ͍ͷ͔ʁʯ ʮͳͥReq/ResΛ࠶ൃ໌ͨ͠ͷ͔ʁʯ » ݁ߏ࢖ͬͨΜͰ͚͢Ͳ…ίʔυ͕௕͘ͳΓ͕ͪʂςετਏ͍ » psr7͸http༻ͳͷͰɺࠓࣗ෼͕΄͍͠΋ͷΑΓϩʔϨϕϧ » ·ͩࢫຯ͕গͳ͍ʂ » ·͋ɺpsr7͕ඞཁʹͳΕ͹Ξμϓλॻ͚Δ

    » Req/ResͰܕΛ͠͹Γ͍ͨཉ͕͋ͬͨ » psr7Λجఈʹ֦ͯ͠ுͮ͠Β͗͢ΔͰ͠ΐ… » ࢓༷ύϫʔϓϨΠରॲͷ୤ग़ϋονΛ࡞ΓͮΒ͍
  116. σʔλ » Service, Repo, Modelͷࡾ૚ » Service: Model/RepoΛ·͙ͨॲཧɺτϥϯβΫ γϣϯΛఆٛͰ͖Δ »

    Repo: SQLΛॻ͘ʢʂʣɺModelΛฦͨ͠ΓɺӬଓ Խ » Model: ໨తͱͯ͠͸ߏ଄ମɺ͍ΖΜͳॴͰҾ਺ͷܕ ͱͯ͠ࢦఆɻ->isEqual($val)ɺ->toArray()ͱ͔ ΦϒδΣΫτΒ͍͠؆୯ͳϩδοΫ΋ؚΉ
  117. Service !"" lib # $"" MyApp # !"" Api #

    # !"" Action # # !"" Request # # $"" Response # !"" Model # !"" Repo # $"" Service !" $"" tests # $"" testTest.php
  118. class UserAccountService { public static function getByEmail(string $email, UserAccountRepo $repo=null):

    ?UserAccount { $repo = $repo ?? new UserAccountRepo(); return $repo->getByEmail($email); } public static function getByEmailAndPassword(string $email, string $password, UserAccountRepo $repo): ?UserAccount { $ua = static::getByEmail($email, $repo); if (is_null($ua)) return null; if (!password_verify($password, $ua->hashed_password)) return null; return $ua; } public static function update(UserAccount $ua, UserAccountRepo $repo = null): bool { $repo = $repo ?? new UserAccountRepo(); return $repo->update($ua); }
  119. » ੩తϝιουͷմ » Action͔Β͸repoΛ৮Βͣɺ͜ΕΛ৮Δ » ϔϏʔͳ໰͍߹Θ͕ͤൃੜ͢Δ৔߹͸ΩϟογϡΛ͜ ͜ʹೖΕΔ͜ͱ΋ » Modelͱ1:1ʹͳΒͳ͍ɺModelʹରͯ͠ෳ਺ͷ Service͕͋Δ͜ͱ΋͋Δ͠ɺService͕ෳ਺ͷ

    ModelΛૢ࡞͢Δ͜ͱ΋͋Δɻ » Service͔ΒServiceΛ৮Δࣄ΋͋Δ
  120. Repo !"" lib # $"" MyApp # !"" Api #

    # !"" Action # # !"" Request # # $"" Response # !"" Model # !"" Repo !" # $"" Service $"" tests # $"" testTest.php
  121. class UserAccountRepo extends DB { public function getByEmail(string $email): ?UserAccount

    { $pdo = static::getPdo(); $stmt = $pdo->prepare("SELECT * FROM `user_account` WHERE email = :email"); $stmt->bindValue('email', $email, \PDO::PARAM_STR); $stmt->execute(); $stmt->setFetchMode(\PDO::FETCH_CLASS, '\MyApp\Model\UserAccount'); return $stmt->fetch() ?: null; } public function create(UserAccount $ua): int { if(!$ua->isValid()) throw new \InvalidArgumentException("invalid user account model"); $pdo = static::getPdo(); $stmt = $pdo->prepare(" INSERT INTO user_account (email, hashed_password, name) VALUES (:email, :hashed_password, :name) "); $stmt->bindValue('hashed_password', $ua->hashed_password, \PDO::PARAM_STR); $stmt->bindValue('name', $ua->name, \PDO::PARAM_STR); $stmt->bindValue('email', $ua->email, \PDO::PARAM_STR); $result = $stmt->execute(); if (!$result) throw new \RuntimeException("DB query error."); return $pdo->lastInsertId('id'); }
  122. » ӬଓԽ΍σʔλͷϩʔυΛ࢘Δ » ModelΛੜ੒ͨ͠ΓɺModelΛอଘͨ͠Γ͢Δ » όϦόϦʹSQLΛॻ͍ͯ΋͍͍͠ɺ֎෦APIΛୟ͘ࣄ ΋͋Δ » ϛεϚονΛٵऩ͢Δ »

    ྫ֎͸جຊ࢖Θͳ͍ɺ0݅औಘͱ͔͸جຊNULLฦ͠ Ͱ্ҐͰڍಈΛ൑ఆ͢Δ » Goͷval, errorΈ͍ͨͳͷ΄͍ͬ͢͠Ͷ… listड ͚Ͱ΋͍͍͚Ͳ…ɻ
  123. » setFetchMode(\PDO::FETCH_CLASS, UserAccount::class);Λଟ༻ » SQLΛੜ੒͠ͳ͍Ͱ͢Ή୯ͳΔ̍ߦηϨΫτ͸SQLख ॻ͖ » SQL͸10೥ઓ͑ΔͷͰ » ෳࡶͳʢͨͱ͑͹ݕࡧʣΫΤϦ͸ݫ͍͠ͷͰSQLϏϧ

    μ΋࢖͏ » nilportugues/php-sql-query-builder » บ΋ଟগ͋Δ͕ɺਖ਼௚ɺܾఆ൛͕ݟ͔ͭΒͳ͍
  124. Service !"" lib # $"" MyApp # !"" Api #

    # !"" Action # # !"" Request # # $"" Response # !"" Model !" # !"" Repo # $"" Service $"" tests # $"" testTest.php
  125. Modelྫ class UserAccount { public $id = 0; public $email

    = ""; public $hashed_password = ""; public $name = ""; public function __construct() { if ($this->id === 0) return; // PDO fetchͳΒҎ߱΋࣮ߦ͞ΕΔ $this->id = (int)$this->id; } public function getPublicData(): array { $list = get_object_vars($this); unset($list['id']); unset($list['hashed_password']); return $list; }
  126. » ཉ͍͠σʔλߏ଄͕͋Ε͹ͭ͘ΔɺςʔϒϧͱҰରҰͰ ରԠඞਢͰ͸ͳ͍ » ϓϩύςΟ͸ඞཁͳ෼ͭ͘ΔɺIDEͷิ׬ʹ΋͔ͭ͏ » ଟ͘ͷέʔεͰ͸ɺίϯετϥΫλ͸FETCH_CLASSܦ༝ Λ૝ఆɺศརʂ » PDO

    FETCH_CLASS͸શ෦strʹͳΔͷͰɺModelͷίϯ ετϥΫλͰม׵ɺ͍ͩ͞ » Typed Properties͕͖ͨΒઈରʹ͜͜Ͳ͏ʹ͔ͳͬ ͯͯ΄͍͠… » ͳ͓ɺhydrate΋(΍Ζ͏ͱ͓΋͑͹)͜͜ͰͰ͖Δ
  127. // ଓ͖ public function setPassword(string $new_plain_password): void { $this->hashed_password =

    password_hash($new_plain_password, PASSWORD_DEFAULT); } public function passwordVerification(string $plain_pass): bool { return password_verify($plain_pass, $this->hashed_password); } public function isValid(): bool { return count($this->validate()) === 0; } public function validate(): array { /* ... লུ ... */ return []; // is OK }
  128. » ͋·Γϝιου͸ੜ΍͞ͳ͍Ͱ͓͘ɺຊ౰ʹ࠷௿ݶ ͷΈॻ͘ » Ϋϥε಺Ͱด͡ΒΕΔΑ͏ͳ؆୯ͳϢʔςΟϦςΟత ͳϝιου͸͜͜ʹੜ΍ͯ͠΋ྑ͍ » generate_uuid,base64url_encode,validate…

  129. σʔλ·ͱΊ » ͱʹ͔͘ܕΛ͚ͭΔ » ྫ֎͸࠷௿ݶʢओ؍ʣ » ฦΓ஋ʹNULLଟ༻͸ɺݹ͍ਓؒͳͷͰؾʹͳΒ ͳ͍ ?Type Έ͍ͨʹ͢Ε͹͍͍͠

    » ʢGoΈ͍ͨʹ(v, err)͍ͨ͠…ʣ
  130. ඒ࣮͘͠૷͍ͨ͠Θ͚Ͱ͸ͳ͍ » ϦϑΝΫλϦϯάͰյΕʹ͍ͨ͘͘͠ » Ͱ͖Δ͚ͩґଘΛ୯ํ޲ʹʢඞͣɺͰ͸ͳ͍ʣ » मਖ਼ͷӨڹ͕޿͘ग़Δ(Ͱͯ͠·͏)ARύλʔϯʹ͸͠ͳ͍ ʢঢ়ଶ͸Ͱ͖Δ͔͗Γ࣋ͨͤͳ͍ɺ͔͠͠Ϧιʔε͕…ʣ » ΄Μ΋ͷͷDataMapper͸ͭΒ͍͆ʢ͋͋ɺΦϨΦϨͩ…

    » ϔϯςίͳHugeͳ࢓༷͕ଞΛߥΒ͞ͳ͍Α͏ʹ͍ͨ͠ » ҟৗͳཁ͕݅ύϫʔϓϨΠͰ͖ͨΒɺ BookInsaneSearchRepoͱ͔ͭͬͯ͘ղܾ͢Δ » ਖ਼ؾͳۭؾʹͳͬͨΒɺࣺͯΔʢͯ͢ΒΕΔͷ͔ʁʣ
  131. » ʢҰൠతͳʣFWͰ΍Δͱɺ΍Γํ͕Θ͔Βͳ͔ͬͨ Γɺศརػೳ͕͔ͭ͑ͳͯ͘͏Μ͟Γ » Θ͔ΒΜʂͱͳͬͯ҆қʹ഑ྻʹม׵ͪ͠Όͬͯ ޙͰഁ໓ʢ͜Ε͸ࢲͷษڧෆ଍ͩʣ » ԕྀͳ͘ɺςʔϒϧ͸ͦͷ··ͰModelʢͱɺR ͱSʣΛ૿΍ͯ͠ରԠ͢ΔɺSQLॻ͘ »

    (γϯϓϧͳSQL Builderಉ༷ʹɺγϯϓϧͳ Hydrater΄͍͠Ͱ͢Ͷ) » Ϟσϧ,DB,(APIͷ)JSONߏ଄Λ߹ΘͤΔن໿ʹҰ୴ ͞ΑͳΒ
  132. » DB(PDO)ΛૉखͰ͔͍͍ͭͨ࣌ʹORM͸͠ΜͲ͍ » ී௨ͷORM͸ςʔϒϧͷΧϥϜͷ૿ݮʹ͸ରԠ͠ ΍͍͕͢ɺӡ༻ϑΣʔζͰ͸ςʔϒϧͷΧϥϜͦ Μͳʹ૿ݮ͠ͳ͍ؾ͕͢Δʢओ؍ʣ » γϯϓϧͳΫΤϦ͸ΫΤϦϏϧμͷඞཁੑ͕͋Μ ·Γͳ͍ »

    ΫΤϦϏϧμ͕bindValueͷܕΛͪΌΜͱ͋ͭ ͔ͬͯ͘Εͳ͍͜ͱ͕ଟ͍… » ʮ͑ͬɺ͜ΕͲ͔͜ΒͲ͜·ͰτϥϯβΫγϣϯͳ ͷʁϩʔϧόοΫ͸ʁʯ
  133. » ViewɺController૚͸৐Γ׵͑΍͍͢ɺಉ͡ϨΠϠ Ͱͷґଘ͕͘͢ͳ͍ » ʢ͍ΘΏΔʣModel͸ॎஅɺԣஅతʹґଘ͢Δ͜ͱ ʹͳΓ͕ͪɺ͜͜͸ૈ৯ʹͨ͠΄͏͕௕ੜ͖ʹ͖͘ ͧʢओ؍