๋ธ”๋กœ๊ทธ

๐Ÿพ Gato GraphQL์ด ์ด์ œ ์Šค์ฝ”ํ•‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. PHP-Scoper ๋•๋ถ„์ž…๋‹ˆ๋‹ค!

Leonardo Losoviz
์ž‘์„ฑ์ž: Leonardo Losoviz ยท

ํ”Œ๋Ÿฌ๊ทธ์ธ Gato GraphQL์ด ์Šค์ฝ”ํ•‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋“œ๋””์–ด WordPress ํ”Œ๋Ÿฌ๊ทธ์ธ ๋””๋ ‰ํ† ๋ฆฌ์— ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋น„์ฆˆ๋‹ˆ์Šค ๋Œ€ํ™”

์ด๋ฅผ ์œ„ํ•ด ํ›Œ๋ฅญํ•œ PHP-Scoper๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ WordPress์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์‰ฝ์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ด ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์„น์…˜:

์Šค์ฝ”ํ•‘์„ ๊ฒฐ์ •ํ•˜๊ธฐ๊นŒ์ง€

๋ช‡ ์ฃผ ์ „, Matt Mullenweg๊ฐ€ ใ€ŒGraphQL ํ”Œ๋Ÿฌ๊ทธ์ธใ€์„ ์ฃผ์‹œํ•˜๊ฒ ๋‹ค๊ณ  ๋ฐœํ‘œํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ช…๋ฐฑํžˆ WPGraphQL์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์˜ ๋ฐœ์–ธ์€ GraphQL ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ํ•˜๋‚˜๋ฟ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Œ์„ ๋ณด์—ฌ์ฃผ์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ๋‘ ๊ฐœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(์ œ์™ธ๋œ ๊ฒƒ์€, ์Œ, ์ œ ๊ฒƒ์ž…๋‹ˆ๋‹ค). ์ด๋ฅผ ํ†ตํ•ด ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์–ผ๋งˆ๋‚˜ ์ฃผ๋ชฉ๋ฐ›์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ๊นจ๋‹ซ๊ฒŒ ๋˜์—ˆ๊ณ , ์”์“ธํ•œ ๋งˆ์Œ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

Matt๋Š” ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์กด์žฌํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. WordPress ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ๋Œ€๋ถ€๋ถ„๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ํ™๋ณด๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งˆ์ผ€ํŒ…๊ณผ ์†Œ์…œ ๋ฏธ๋””์–ด๋Š” ์ œ ๊ฐ•์ ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ธฐ์ˆ ์ ์ธ ๋ถ€๋ถ„์€ ๊ทธ๋Ÿฐ๋Œ€๋กœ ์ž˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ์š”. ๊ทธ๋ž˜์„œ ์ตœ์†Œํ•œ ์ œ ๋Šฅ๋ ฅ ๋ฒ”์œ„ ๋‚ด์—์„œ ๋ฌด์–ธ๊ฐ€ ํ–‰๋™ํ•˜๊ธฐ๋กœ ๊ฒฐ์‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š” ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ด ์›น์‚ฌ์ดํŠธ gatographql.com์˜ ์ฝ”๋”ฉ์„ ๋ฐฉ๊ธˆ ๋งˆ์น˜๊ณ  2์ฃผ ์ „์— ์ถœ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค(๋งŒ์„ธ! ๐Ÿฅณ ๊ทธ๋Ÿฐ๋ฐ, ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? DM์ด๋‚˜ ์ด๋ฉ”์ผ๋กœ ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค)
  • 3์ผ ์ „์— ๋“œ๋””์–ด ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค์ฝ”ํ•‘์„ ์‹œ์ž‘ํ–ˆ๊ณ , ์–ด์ œ ์ด ์ž‘์—…์„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค!(์ƒˆ๋ฒฝ 3์‹œ์˜€์ง€๋งŒ, ํ•  ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜…)
  • ๋งˆ์ง€๋ง‰์œผ๋กœ, ๋‹ค์Œ ๋ฒ„์ „ 0.8 ์ž‘์—…์„ ์ด๋ฏธ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ ์ €์žฅ์†Œ์—์„œ ์ฒ˜์Œ์œผ๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•œ ๋ฒ„์ „์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค

ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์Šค์ฝ”ํ•‘ํ•˜๋Š” ๊ฒƒ์€ ์ €์žฅ์†Œ์— ์—…๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•œ ํ•„์ˆ˜ ์กฐ๊ฑด์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ๋™์ผํ•œ ์˜์กด์„ฑ์„ ํ•„์š”๋กœ ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ๋ฒ„์ „์„ ๊ฐ€์ง„ ๋‹ค๋ฅธ ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ์™„๋ฃŒํ•œ ๊ฒƒ์€ ์ •๋ง ์ค‘์š”ํ•œ ์ด์ •ํ‘œ์ž…๋‹ˆ๋‹ค. ์ด๋ณด๋‹ค ์ค‘์š”ํ•œ ๊ฐœ๋ฐœ์€ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, WordPress ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๊ณผ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๋„๋ก GraphQL ์Šคํ‚ค๋งˆ๋ฅผ ์™„์„ฑํ•ด์•ผ ํ•˜์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ๊ฐ๊ฐ์˜ ์ƒˆ ๋ฆด๋ฆฌ์Šค์—์„œ ๊พธ์ค€ํžˆ ์ง„ํ–‰๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ช‡ ์ฃผ ํ›„์—๋Š” ใ€ŒGraphQLใ€๋กœ ๊ฒ€์ƒ‰ํ–ˆ์„ ๋•Œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋˜๊ณ , GraphQL API ๊ตฌํ˜„์„ ์‹ค์ œ๋กœ ํ•„์š”๋กœ ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ์กด์žฌ๋ฅผ ์•Œ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ, ์ €๋Š” ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด WordPress์˜ ๋ฏธ๋ž˜์—์„œ ์ง„์ง€ํ•˜๊ฒŒ ๊ณ ๋ ค๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ๋™์•ˆ ์ž‘์—…ํ•ด ์™”์Šต๋‹ˆ๋‹ค. ์ €์žฅ์†Œ๋Š” 2016๋…„ 8์›”์— ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” WPGraphQL์ด ์กด์žฌํ•˜๊ธฐ ์ „์ด๋ฉฐ, GraphQL์˜ ์ดˆ์ฐฝ๊ธฐ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ GraphQL ์„œ๋ฒ„๊ฐ€ ๋  ์ค„์€ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ๊ทธ ๋ฐฉํ–ฅ์œผ๋กœ ์ „ํ™˜๋œ ๊ฒƒ์€ ๋ถˆ๊ณผ 1.5๋…„ ์ „์˜ ์ผ์ž…๋‹ˆ๋‹ค.

(์ด ํ”„๋กœ์ ํŠธ๋Š” ์‹ค์ œ๋กœ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋ฉฐ, ์ด ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด GraphQL ์„œ๋ฒ„๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ทธ๋ƒฅ ๊ตฌ์ถ•ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

WPGraphQL์€ ํ™•๋ฆฝ๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋ฉฐ, ๊ทธ๋Ÿด ๋งŒํ•œ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ์ „์— ์‹œ์ž‘๋˜์–ด ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ํ˜•์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Jason Bahl(Gatsby์— ๊ณ ์šฉ๋œ)๊ณผ ํ”„๋กœ์ ํŠธ์˜ ๊ธฐ์—ฌ์ž๋“ค์˜ ์ž‘์—…์€ ํƒ์›”ํ–ˆ์Šต๋‹ˆ๋‹ค. WordPress๋ฅผ Jamstack์— ํ†ตํ•ฉํ•˜๋Š” ๊ฒƒ์ด ์–ด๋А ๋•Œ๋ณด๋‹ค ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ Gatsby์™€ Jamstack์€ ํ•œ ๊ฐ€์ง€์ด๊ณ , WordPress๋Š” ๋‹ค๋ฅธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. WordPress๋Š” ์›น์˜ 40%๋ฅผ ์ฐจ์ง€ํ•˜๋ฉฐ, ๋‹จ์ˆœํžˆ ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ๊ธฐ์˜ ์ž…๋ ฅ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด์ œ ๋Œ€์•ˆ์ด ์—†์–ด์„œ ์ด ๊ฒฐ์ •์ด ๊ฐ•์š”๋˜๋Š” ๊ฒƒ ์—†์ด, WPGraphQL์ด ์˜ฌ๋ฐ”๋ฅธ ์„ ํƒ์ธ์ง€ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋ถ„์„ํ•˜์—ฌ ์–ด๋А ์ชฝ์˜ ๋ชฉํ‘œ๊ฐ€ WordPress์— ์ค‘์š”ํ•œ ๊ฒƒ๊ณผ ๋” ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Gato GraphQL๋„ Jamstack๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ์ฃผ์š” ๋ชฉํ‘œ๋Š” ๋” ํ›Œ๋ฅญํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ใ€Œ๋ฐ์ดํ„ฐ ๊ฒŒ์‹œ๋ฅผ ๋ฏผ์ฃผํ™”ใ€ํ•˜๋Š” ๊ฒƒ, ์ฆ‰ API ํŽธ์ง‘์„ ๊ฒŒ์‹œ๋ฌผ ํŽธ์ง‘๋งŒํผ ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ(๋ˆ„๊ตฌ๋‚˜ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ), ๊ทธ๋ฆฌ๊ณ  WordPress๋ฅผ ์›น์˜ OS๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์ €์žฅ์†Œ์—์„œ ์ด์šฉ ๊ฐ€๋Šฅํ•ด์ง€๋ฉด, ๋” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‹œ๋„ํ•ด ๋ณด๊ณ  ใ€Œ์ด๊ฑฐ ์ •๋ง ๋Œ€๋ฐ•์ด๋„ค! ์™œ ์ด๋Ÿฐ ๊ฑธ ๋ชฐ๋ž์„๊นŒ?ใ€๋ผ๊ณ  ๋งํ•ด์ฃผ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ใ€ŒGraphQL ํ”Œ๋Ÿฌ๊ทธ์ธใ€์˜ ์„ ํƒ์€ ๋ฏธ๋ฆฌ ๊ฒฐ์ •๋˜์ง€ ์•Š๊ณ , WordPress ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ WPGraphQL๊ณผ Gato GraphQL ๋ชจ๋‘๋ฅผ ๊ฐ๊ฐ์˜ ์žฅ์ ์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋™๊ธฐ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ๋๋‚ฌ์œผ๋‹ˆ, ๊ธฐ์ˆ ์ ์ธ ์ด์•ผ๊ธฐ๋ฅผ ํ•ด๋ด…์‹œ๋‹ค ๐Ÿค“.

์˜ต์…˜ ๊ฒ€ํ† 

ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค์ฝ”ํ•‘์€ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„ ์Šค์ฝ”ํ•‘๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ถœ๋ ฅํ•˜๋Š” ๋„๊ตฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๋ณ„๊ฑฐ ์•„๋‹ˆ์ฃ ? ์–ผ๋งˆ๋‚˜ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์„๊นŒ์š”?

๊ธฐ์ˆ ์ ์ธ ๋Œ€ํ™”

์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋”ฐ๋ผ, ์Šค์ฝ”ํ•‘ ๋ช…๋ น๋งŒ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ํ›„์—๋Š” ์ฝ˜์†”์˜ ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•˜๊ณ , ์ˆ˜์ •ํ•˜๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ฒ ์ €ํžˆ ํ…Œ์ŠคํŠธํ•˜๊ณ , ์˜ค๋ฅ˜์™€ ๊ทธ ์›์ธ์„ ํŒŒ์•…ํ•˜๊ณ , ์ˆ˜์ •ํ•˜๊ณ , ๋ฐ˜๋ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์™„์ „ํžˆ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋А ์ •๋„์˜ ์‹œ๊ฐ„์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Šค์ฝ”ํ•‘์„ ์œ„ํ•œ 2๊ฐœ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋ชฉ์ ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  • Mozart, WordPress ์ฝ”๋“œ์šฉ
  • PHP-Scoper, ๋ชจ๋“  PHP ์ฝ”๋“œ์šฉ. ํŠนํžˆ PHAR์„ ์ƒ์„ฑํ•  ๋•Œ

WordPress ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ๋จผ์ € Mozart๋ฅผ ์‹œ๋„ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๋˜์—ˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Mozart๋ฅผ ์‹œ๋„ํ•˜๊ณ  ์‹คํŒจํ•˜๋‹ค

์•ฝ 1๋…„ ์ „์— Mozart๋ฅผ ์‹œ๋„ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด ใ€Œmozart compose ๋ช…๋ น์ด ๋ชจ๋“  ๋งˆ๋ฒ•์„ ์ˆ˜ํ–‰ํ•œ๋‹คใ€๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ชจ๋“  ๊ฒƒ์ด ๋งค์šฐ ๋น ๋ฅด๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐ๋˜์–ด ๋‚˜๋จธ์ง€ ํ•˜๋ฃจ๋ฅผ ๋‹ค์ดํ‚ค๋ฆฌ๋ฅผ ์ฆ๊ธฐ๋ฉฐ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

์•ˆํƒ€๊น๊ฒŒ๋„, Mozart๋Š” ์ œ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ณ„์† ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์Šค์ฝ”ํ•‘์ด ์‹คํ˜„๋˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ์ง€์›๋„ ๋ฐ›์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. PR์„ ์ œ์ถœํ–ˆ์ง€๋งŒ ๋ณ‘ํ•ฉ์ด ๊ณ ๋ ค๋˜์ง€ ์•Š์•˜๊ณ , ๊ทธ ์‚ฌ์‹ค์กฐ์ฐจ ํ†ต์ง€๋ฐ›์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ๊ด€์‹ฌ์„ ์žƒ์„ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Mozart๊ฐ€ ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ์ผ๋ถ€ ์˜์กด์„ฑ์„ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Symfony์˜ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, DependencyInjection, Cache, Dotenv๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, ๋ชจ๋‘ Composer๋กœ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

PHP ์Šค์ฝ”ํ•‘์€ ๋‹จ์ˆœํžˆ PHP๋งŒ์˜ ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์Šค์ฝ”ํผ์—๋Š” ํ”ผํ•ด์•ผ ํ•  ๋งŽ์€ ์žฅ์• ๋ฌผ๊ณผ ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๊ณผ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Symfony DependencyInjection์€ ์„ค์ •์— YAML ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๊ฒƒ๋“ค๋„ ์Šค์ฝ”ํ•‘๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ composer.json ํŒŒ์ผ์—๋Š” PSR-4 ์ž๋™ ๋กœ๋”ฉ ์„ค์ •์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ด๊ฒƒ๋„ ์Šค์ฝ”ํ•‘๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Mozart๋Š” ์ด๋Ÿฌํ•œ ๋ณต์žก์„ฑ์„ ์ œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ œ ๊ฒฝํ—˜๋งŒ์ด ์œ ์ผํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋ผ๊ณ  ํ™•์‹ ํ•˜๋ฉฐ, ๋งŒ์กฑํ•˜๋Š” ์‚ฌ์šฉ์ž๋“ค๋„ ๋งŽ์ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ œ ์‹คํŒจํ•œ ์‹œ๋„๋Š” 1๋…„ ์ „์˜ ์ผ์ด๋ฏ€๋กœ, ๊ทธ ์ดํ›„๋กœ ๋„๊ตฌ๊ฐ€ ๊ฐœ์„ ๋˜์—ˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์žŠ์ง€ ๋งˆ์„ธ์š”. ใ€Œ์Šค์ฝ”ํ•‘๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๋ชจ๋‘ ๋น„์Šทํ•˜๋‹ค. ์Šค์ฝ”ํ•‘๋˜์ง€ ์•Š์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๊ฐ์ž ๋…์ž์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์Šค์ฝ”ํ•‘๋˜์ง€ ์•Š๋Š”๋‹คใ€๋Š” ๋ง์ฒ˜๋Ÿผ, ์–ด์ฉŒ๋ฉด ์ €๋งŒ์˜ ๋ฌธ์ œ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

WordPress ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋‹จ์ˆœํ•˜๊ณ  ์ž์ฒด ์™„๊ฒฐ์ ์ธ ๋กœ์ง์„ ๊ฐ€์ง€๋ฉฐ, ์Šค์ฝ”ํ•‘์ด PHP ์ฝ”๋“œ ๋‚ด์—์„œ๋งŒ ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด Mozart๊ฐ€ ์ž‘๋™ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ง์ ‘ ํ™•์ธํ•ด ๋ณด๋Š” ์ˆ˜๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค.

PHP-Scoper๋ฅผ ํ™•์ธํ•˜๊ณ  ๊ณตํ™ฉ ์ƒํƒœ์— ๋น ์ง€๋‹ค

๊ทธ๋ž˜์„œ PHP-Scoper๋กœ ํ–ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฆ‰์‹œ ๊ฒ์ด ๋‚˜์„œ ์‹œ๋„์กฐ์ฐจ ํ•ด๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ €, ์ด ๋„๊ตฌ๋Š” WordPress๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ณ„์†ํ•ด์„œ, ๊ทธ๋“ค ์ž์‹ ์˜ Makefile์„ ์‚ดํŽด๋ณผ ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๋Š”๋ฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ชจ์Šต์ž…๋‹ˆ๋‹ค.

# See https://tech.davis-hansson.com/p/make/
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
 
.DEFAULT_GOAL := help
 
PHPBIN=php
PHPNOGC=php -d zend.enable_gc=0
IS_PHP8=$(shell php -r "echo version_compare(PHP_VERSION, '8.0.0', '>=') ? 'true' : 'false';")
 
SRC_FILES=$(shell find bin/ src/ -type f)
 
.PHONY: help
help:
	@echo "\033[33mUsage:\033[0m\n  make TARGET\n\n\033[32m#\n# Commands\n#---------------------------------------------------------------------------\033[0m\n"
	@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' | awk 'BEGIN {FS = ":"}; {printf "\033[33m%s:\033[0m%s\n", $$1, $$2}'
 
 
#
# Build
#---------------------------------------------------------------------------
 
.PHONY: clean
clean:	 ## Clean all created artifacts
clean:
	git clean --exclude=.idea/ -ffdx
 
update-root-version: ## Check the lastest GitHub release and update COMPOSER_ROOT_VERSION accordingly
update-root-version:
	rm .composer-root-version || true
	$(MAKE) .composer-root-version

๊ทธ๋ฆฌ๊ณ  600์ค„ ์ด์ƒ, ๋ชจ๋‘ ์ด๋Ÿฐ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ๋งˆ์น˜ ์ˆ˜์ˆ˜๊ป˜๋ผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์Šค์ฝ”ํ•‘ํ•˜๊ธฐ ์œ„ํ•ด ๊ทธ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋‹ˆ, ํ™ฉ๊ธ‰ํžˆ ๋„๋ง์ณค์Šต๋‹ˆ๋‹ค.

(์Œ, ๊ทธ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์Šค์ฝ”ํ•‘๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•œ ๊ถŒ์žฅ ์‚ฌํ•ญ์ด์ง€, ํ•„์ˆ˜๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ php-scoper add-prefix ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ณ , ๋ชจ๋“  ๋งˆ๋ฒ•์„ ๋งก๊ธฐ๊ณ , ๋‹ค์ดํ‚ค๋ฆฌ๋ฅผ ๋งˆ์‹œ๋Ÿฌ ๊ฐˆ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.)

PHP-Scoper๋กœ ๋Œ์•„์˜ค๋‹ค, ์ด๋ฒˆ์—๋Š” ์ง„์‹ฌ์œผ๋กœ

3์ผ ์ „, ์–ด๋–ป๊ฒŒ๋“  ์Šค์ฝ”ํ•‘์„ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ๊ฒฐ์‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ์‹คํ˜„์‹œ์ผœ์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

PHP-Scoper๋กœ ๋Œ์•„์™€์„œ ์ง„์ง€ํ•˜๊ฒŒ ์‹œ๋„ํ•ด ๋ณด๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. PHP Scoper: How to Avoid Namespace Issues in your Composer Dependencies(Delicious Brains์˜ ํ›Œ๋ฅญํ•œ ํŒ€์ด ์ž‘์„ฑํ•œ)๋ฅผ ์ฝ๊ณ  WordPress๋ฅผ ์Šค์ฝ”ํ•‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ํƒœ๋„์™€ ๋ˆ๊ธฐ์˜ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ์†”๋ฃจ์…˜๋“ค์„ ํƒ์ƒ‰ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ชจ๋‘ ์™„์ „ํžˆ ๋งŒ์กฑ์Šค๋Ÿฝ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ํ•ดํ‚น์ฒ˜๋Ÿผ ๋ณด์ด๊ฑฐ๋‚˜, ์ทจ์•ฝํ•˜๊ณ  ์–ธ์  ๊ฐ€ ๊นจ์งˆ ๊ฒƒ ๊ฐ™์€ ๊ฒƒ๋“ค์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, Google Web Stories ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์ฝ”๋“œ๋ฅผ ์Šค์ฝ”ํ•‘ํ•œ ๋‹ค์Œ, ๊ฐ ์ถฉ๋Œ์„ ๋‹ค์‹œ ๋˜๋Œ๋ฆฝ๋‹ˆ๋‹ค.

return [
  'patchers'                   => [
		function ( $file_path, $prefix, $contents ) {
			/*
			 * There is currently no easy way to simply whitelist all global WordPress functions.
			 *
			 * This list here is a manual attempt after scanning through the AMP plugin, which means
			 * it needs to be maintained and kept in sync with any changes to the dependency.
			 *
			 * As long as there's no built-in solution in PHP-Scoper for this, an alternative could be
			 * to generate a list based on php-stubs/wordpress-stubs. devowlio/wp-react-starter/ seems
			 * to be doing just this successfully.
			 *
			 * @see https://github.com/humbug/php-scoper/issues/303
			 * @see https://github.com/php-stubs/wordpress-stubs
			 * @see https://github.com/devowlio/wp-react-starter/
			 */
			$contents = str_replace( "\\$prefix\\_doing_it_wrong", '\\_doing_it_wrong', $contents );
			$contents = str_replace( "\\$prefix\\__", '\\__', $contents );
			$contents = str_replace( "\\$prefix\\esc_html_e", '\\esc_html_e', $contents );
			$contents = str_replace( "\\$prefix\\esc_html", '\\esc_html', $contents );
			$contents = str_replace( "\\$prefix\\esc_attr", '\\esc_attr', $contents );
			$contents = str_replace( "\\$prefix\\esc_url", '\\esc_url', $contents );
      $contents = str_replace( "\\$prefix\\do_action", '\\do_action', $contents );
      // ...
    }
  ]
]

์™œ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜์ง€๋งŒ, ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด WordPress ํ•จ์ˆ˜๊ฐ€ ์ฐธ์กฐ๋  ๋•Œ๋งˆ๋‹ค ์ด ๋ชฉ๋ก์—๋„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ์ˆ˜๋™์ ์ด๊ณ , ๋„ˆ๋ฌด ์ทจ์•ฝํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ œ ๊ณผ์ œ์˜€์Šต๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์Šค์ฝ”ํ•‘ํ•˜๋Š” ๋” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ๊ณ , ์นœ๊ตฌ๋‚˜ ๋™๋ฃŒ์—๊ฒŒ ๋ณด์—ฌ์ค˜๋„ ๋ถ€๋„๋Ÿฝ์ง€ ์•Š์€ ์ฝ”๋“œ์— ์˜์กดํ•  ์ˆ˜ ์—†์„๊นŒ์š”?

PHP-Scoper, ์‰ฌ์šด ๋ฐฉ๋ฒ• ๐Ÿ˜Ž

์ƒ๊ฐ๋ณด๋‹ค ํ›จ์”ฌ ์‰ฌ์› ์Šต๋‹ˆ๋‹ค! ๋‹จ ๋ช‡ ์‹œ๊ฐ„ ๋งŒ์— ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ช‡ ์‹œ๊ฐ„ ๋งŒ์— ์Šค์ฝ”ํ•‘

ใ€Œ์‰ฝ๋‹คใ€์™€ ใ€Œ๋ช‡ ์‹œ๊ฐ„ใ€์ด๋ผ๊ณ  ๋งํ•  ๋•Œ, ์‹ค์ œ๋กœ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฒ ์ด์Šค์— ์ ์ ˆํ•œ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ 2๊ฐœ์›”์„ ๋ณด๋‚ธ ํ›„์—์•ผ ๋ชจ๋“  ๊ฒƒ์ด ์ฆ‰์‹œ ์ž‘๋™ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(๋‚˜์ค‘์— ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค).

ํ•˜์ง€๋งŒ ์ค‘์š”ํ•œ ๊ฒƒ์€, ํ”„๋กœ์ ํŠธ์˜ ์˜ฌ๋ฐ”๋ฅธ ์„ค์ •์ด ์žˆ๋‹ค๋ฉด ์Šค์ฝ”ํ•‘์€ ๊ธˆ๋ฐฉ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

WordPress ์ฝ”๋“œ๋ฅผ ์Šค์ฝ”ํ•‘ํ•  ๋•Œ์˜ ๋ฌธ์ œ๋Š” ๋ฐ”๋กœ WordPress ์ฝ”๋“œ ์ž์ฒด์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์—ฌ๊ธฐ์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์•ฝํ•˜๋ฉด, ๋ชจ๋“  WordPress ํ•จ์ˆ˜์™€ ํด๋ž˜์Šค๋„ ๋„ค์ž„์ŠคํŽ˜์ด์Šคํ™”๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ WP_Query๋ฅผ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜ get_posts๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์ด๊ฒƒ๋“ค์ด MyPrefixedNamespace\WP_Query์™€ MyPrefixedNamespace\get_posts๋กœ ๋ณ€ํ™˜๋˜์–ด ๋Ÿฐํƒ€์ž„์— ๋Œ€์‹คํŒจ๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ PHP-Scoper์—์„œ ํ•ดํ‚น ์—†์ด๋Š” ํ”ผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด, ํ•ด๊ฒฐ์ฑ…์€ ๋ฌด์—‡์ผ๊นŒ์š”? ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์Šค์ฝ”ํ•‘๋  ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ WP_Query๋ฅผ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜, get_posts๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜, ์–ด๋–ค WordPress ์ฝ”๋“œ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ € ๋ฏธ์นœ ๊ฑด๊ฐ€์š”?

์•„๋‹ˆ์š”, ์ €๋Š” ๋ฏธ์น˜์ง€ ์•Š์•˜๊ณ , ์—ฌ๋Ÿฌ๋ถ„๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋„ค, WordPress ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค... ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ WordPress ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์„๊นŒ์š”? ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ 2์„ธํŠธ์˜ ํŒจํ‚ค์ง€๋กœ ๋ถ„ํ• ํ•จ์œผ๋กœ์จ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  • WordPress ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜์ง€๋งŒ, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ๊ฒƒ
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•˜์ง€๋งŒ, WordPress ์ฝ”๋“œ๋ฅผ ์ „ํ˜€ ํฌํ•จํ•˜์ง€ ์•Š๊ณ , ํ•„์š”ํ•œ ์˜์กด์„ฑ๊ณผ ํ•ด๋‹น ์ฝ”๋“œ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, ๋‹จ์ผ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๊ฐ–๋Š” ๋Œ€์‹  ์—ฌ๋Ÿฌ ์ฝ”๋“œ๋ฒ ์ด์Šค(๋˜๋Š” ํŒจํ‚ค์ง€)๋ฅผ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ถ€๋Š” ์Šค์ฝ”ํ•‘๋˜๊ณ  ์ผ๋ถ€๋Š” ์Šค์ฝ”ํ•‘๋˜์ง€ ์•Š์œผ๋ฉฐ, ๋ชจ๋‘ Composer๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋˜์–ด ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด WordPress ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ํŒจํ‚ค์ง€๋Š” ์Šค์ฝ”ํ•‘ํ•˜์ง€ ์•Š์•„ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜๋Š” ์ด์œ ๋Š” ์™ธ๋ถ€ ์˜์กด์„ฑ์— ์†ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์ฐธ์กฐ๋Š” MyNamespace\MyPlugin\MyClass์™€ ๊ฐ™์€ ๋‚ด๋ถ€ ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ๋“ค์€ ์Šค์ฝ”ํ•‘ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. WordPress ์‚ฌ์ดํŠธ์—๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ๋ฒ„์ „์ด ํ•˜๋‚˜๋งŒ ์„ค์น˜๋  ๊ฒƒ์ด๋ผ๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ž์‹ ์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค MyNamespace\*๋ฅผ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋”๋ถˆ์–ด, ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์ž์‹ ์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Gato GraphQL์˜ ํ•„๋“œ ๋ฆฌ์กธ๋ฒ„๋Š” ํด๋ž˜์Šค PoP\ComponentModel\FieldResolvers\AbstractFieldResolver๋ฅผ ํ™•์žฅํ•˜์—ฌ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ์Šค์ฝ”ํ•‘ํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๋“ค์€ ๊ฐœ๋ฐœ ์‹œ์—๋Š” PoP\ComponentModel\FieldResolvers\AbstractFieldResolver๋ฅผ ์ฐธ์กฐํ•˜๊ณ , ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” PrefixedByPoP\PoP\ComponentModel\FieldResolvers\AbstractFieldResolver๋ฅผ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•˜์ง€๋งŒ WordPress ์ฝ”๋“œ๋Š” ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ํŒจํ‚ค์ง€๋งŒ ์Šค์ฝ”ํ•‘ํ•ฉ๋‹ˆ๋‹ค.

์š”์•ฝํ•˜๋ฉด, ์ด ์ „๋žต์„ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

ใ€Œ๋‹จ์ผ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๊ฐ–๊ณ , ์Šค์ฝ”ํ•‘ํ•œ ๋‹ค์Œ, ์—„์ฒญ๋‚œ ๊ณ ํ†ต๊ณผ ์ธ๋‚ด๋กœ ํ”ผํ•ด๋ฅผ ์›๋ž˜๋Œ€๋กœ ๋˜๋Œ๋ฆฌ๊ณ , ์ถฉ๋Œ์ด ๋ˆˆ์— ๋„์ง€ ์•Š์•„ ํ”„๋กœ๋•์…˜์—์„œ ๐Ÿ’ฃ ํญ๋ฐœํ•˜์ง€ ์•Š๊ธฐ๋ฅผ ๊ธฐ๋„ํ•œ๋‹คใ€

์ด๊ฒƒ์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

ใ€Œ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ 2๊ฐœ์˜ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ„๊ณ , ์™ธ๋ถ€ ์˜์กด์„ฑ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•˜๊ณ  WordPress ์ฝ”๋“œ๋Š” ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๋งŒ ์Šค์ฝ”ํ•‘ํ•œ ๋‹ค์Œ, ์ˆ˜๊ณ ํ•œ ๋‹ค์ดํ‚ค๋ฆฌ๋ฅผ ๋งˆ์‹œ๋Ÿฌ ๊ฐ„๋‹ค ๐Ÿนใ€

์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ์„ธ์š”

์†Œ์‹œ์ง€๋ฅผ ์—ด์–ด์„œ ์ง„์งœ ๊ณ ๊ธฐ๊ฐ€ ๋“ค์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค ๐ŸŒญ.

4์ผ ์ „, ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์—๋Š” ๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

namespace GraphQLAPI\GraphQLAPI\ContentProcessors;
 
use Parsedown;
 
class MarkdownContentParser
{
  protected function getHTMLContent(string $fileContent): string
  {
    return (new Parsedown())->text($markdownContent);
  }
}

ํด๋ž˜์Šค Parsedown์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ composer.json์— ์ •์˜๋œ ์™ธ๋ถ€ ์˜์กด์„ฑ erusev/parsedown์—์„œ ์˜ต๋‹ˆ๋‹ค.

{
  "require": {
    "erusev/parsedown": "^1.7"
  }
}

๋”ฐ๋ผ์„œ ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์—๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์Šค์ฝ”ํ•‘ํ•˜์—ฌ Parsedown์„ PrefixedByPoP\Parsedown์œผ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ํ”Œ๋Ÿฌ๊ทธ์ธ ๋‚ด์˜ ๋ชจ๋“  WordPress ์ฝ”๋“œ๋„ ์Šค์ฝ”ํ•‘๋˜์–ด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ฝ”๋“œ๋ฅผ graphql-api/markdown-convertor๋ผ๋Š” ๋ณ„๋„์˜ ํŒจํ‚ค์ง€๋กœ ์ถ”์ถœํ•˜๊ณ , composer.json์˜ ์„œ๋“œํŒŒํ‹ฐ ์˜์กด์„ฑ์„ ์ž์‹ ์˜ ์˜์กด์„ฑ์œผ๋กœ ๊ต์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค.

{
  "require": {
    "graphql-api/markdown-convertor": "^0.8"
  }
}

์ด์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง์ ‘ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ , ๋Œ€์‹  ์ƒˆ ํŒจํ‚ค์ง€์˜ ์„œ๋น„์Šค MarkdownConvertorInterface๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

namespace GraphQLAPI\GraphQLAPI\ContentProcessors;
 
use GraphQLAPI\MarkdownConvertor\MarkdownConvertorInterface;
 
class MarkdownContentParser extends AbstractContentParser
{
    protected MarkdownConvertorInterface $markdownConvertorInterface;
 
    function __construct(MarkdownConvertorInterface $markdownConvertorInterface)
    {
        $this->markdownConvertorInterface = $markdownConvertorInterface;
    }
 
    protected function getHTMLContent(string $fileContent): string
    {
        return $this->markdownConvertorInterface->convertMarkdownToHTML($fileContent);
    }
}

์„œ๋“œํŒŒํ‹ฐ ์˜์กด์„ฑ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋Š” ์ƒˆ ํŒจํ‚ค์ง€์—์„œ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

namespace GraphQLAPI\MarkdownConvertor;
 
use Parsedown;
 
class MarkdownConvertor implements MarkdownConvertorInterface
{
  public function convertMarkdownToHTML(string $markdownContent): string
  {
    return (new Parsedown())->text($markdownContent);
  }
}

์ตœ์ข…์ ์œผ๋กœ, ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์˜์กด์„ฑ graphql-api/markdown-convertor๋ฅผ ์Šค์ฝ”ํ•‘
  • ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฝ”๋“œ์˜ ์Šค์ฝ”ํ•‘ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
  • ์ž์‹ ์˜ ํด๋ž˜์Šค๊ฐ€ ์Šค์ฝ”ํ•‘๋˜์ง€ ์•Š๋„๋ก ๋„ค์ž„์ŠคํŽ˜์ด์Šค GraphQLAPI\*๋ฅผ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋ก

์ด๊ฒƒ์ด ๊ธฐ๋ณธ ์ „๋žต์ž…๋‹ˆ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์Šค์ฝ”ํ•‘๋  ์ˆ˜ ์žˆ์„ ๋•Œ๊นŒ์ง€ ๋ชจ๋“  ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ์ฝ”๋“œ์—์„œ ์ œ๊ฑฐํ•˜๋ฉด์„œ ์ด ๋™์ผํ•œ ์•„์ด๋””์–ด๋ฅผ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

์ถ”์ถœํ•ด์•ผ ํ•  ์˜์กด์„ฑ์€ composer.json ํŒŒ์ผ์˜ require ์„น์…˜์— ์žˆ๋Š” ๊ฒƒ๋“ค๋ฟ์ž…๋‹ˆ๋‹ค. require-dev์˜ ๊ฒฝ์šฐ ์™ธ๋ถ€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ์˜์กด์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์— ์‚ฌ์šฉ๋˜๋Š” ์˜์กด์„ฑ์€ ์Šค์ฝ”ํ•‘ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ, ํ”„๋กœ๋•์…˜์šฉ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋งŒ๋“ค๊ณ  ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ๋“ค๋งŒ ์Šค์ฝ”ํ•‘ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ, ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ composer.json์—๋Š” ์™ธ๋ถ€ ์˜์กด์„ฑ์ด ํฌํ•จ๋˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ œ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ๊ฒฝ์šฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
  "require": {
    "php": "^7.4|^8.0",
    "getpop/engine-wp": "^0.8",
    "graphql-api/markdown-convertor": "^0.8",
    "graphql-by-pop/graphql-clients-for-wp": "^0.8",
    "graphql-by-pop/graphql-endpoint-for-wp": "^0.8",
    "graphql-by-pop/graphql-server": "^0.8",
    "pop-schema/basic-directives": "^0.8",
    "pop-schema/comment-mutations-wp": "^0.8",
    "pop-schema/commentmeta-wp": "^0.8",
    "pop-schema/comments-wp": "^0.8",
    "pop-schema/custompost-mutations-wp": "^0.8",
    "pop-schema/custompostmedia-mutations-wp": "^0.8",
    "pop-schema/custompostmedia-wp": "^0.8",
    "pop-schema/custompostmeta-wp": "^0.8",
    "pop-schema/generic-customposts": "^0.8",
    "pop-schema/media-wp": "^0.8",
    "pop-schema/pages-wp": "^0.8",
    "pop-schema/post-mutations": "^0.8",
    "pop-schema/post-tags-wp": "^0.8",
    "pop-schema/posts-wp": "^0.8",
    "pop-schema/taxonomymeta-wp": "^0.8",
    "pop-schema/taxonomyquery-wp": "^0.8",
    "pop-schema/user-roles-access-control": "^0.8",
    "pop-schema/user-roles-wp": "^0.8",
    "pop-schema/user-state-mutations-wp": "^0.8",
    "pop-schema/user-state-wp": "^0.8",
    "pop-schema/usermeta-wp": "^0.8",
    "pop-schema/users-wp": "^0.8"
  }
}

์ด ํŒจํ‚ค์ง€๋“ค์€ ๋ชจ๋‘ ๋„ค์ž„์ŠคํŽ˜์ด์Šค getpop, graphql-api, graphql-by-pop, pop-schema๋ฅผ ๊ฐ€์ง„ ์ œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ์˜์กด์„ฑ๋“ค์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ๋” ์ž˜ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ๋ถ„์‚ฐ๋˜์–ด ์žˆ์ง€๋งŒ, ๊ทธ๋Ÿด ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋‹จ์ผ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋„ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์˜ ํŒจํ‚ค์ง€ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ, ๋ชจ๋“  ํŒจํ‚ค์ง€๋ฅผ ๋ชจ๋…ธ๋ฆฌํฌ์— ํ˜ธ์ŠคํŒ…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์—ฌ๋Ÿฌ ํŒจํ‚ค์ง€๋ฅผ ํฌํ•จํ•˜๋Š” ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๋‹ค๊ฐ€ ๋ฏธ์ณ๋ฒ„๋ฆด ๊ฒƒ์ž…๋‹ˆ๋‹ค(๋ฏฟ์–ด ์ฃผ์„ธ์š”, ๊ฒฝํ—˜ํ•ด ๋ดค์Šต๋‹ˆ๋‹ค). ์ œ ๊ฒฝ์šฐ, ๋ชจ๋“  ํŒจํ‚ค์ง€๋Š” GatoGraphQL/GatoGraphQL ๋ชจ๋…ธ๋ฆฌํฌ์— ํ˜ธ์ŠคํŒ…๋˜์–ด ์žˆ์œผ๋ฉฐ, ํ›Œ๋ฅญํ•œ Monorepo Builder๋กœ ๋™๊ธฐํ™”๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์ด ๋„๊ตฌ์— ๋Œ€ํ•œ ๊ธ€์„ ์จ์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ •๋ง ์ƒ๋ช…์˜ ์€์ธ์ž…๋‹ˆ๋‹ค!).

์ด ํŒจํ‚ค์ง€๋“ค์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” PoP, GraphQLAPI, GraphQLByPoP, PoPSchema์ž…๋‹ˆ๋‹ค. ์ œ ๊ฒƒ์ด๋ฏ€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•œ ๋ฒˆ๋งŒ ๋‚˜ํƒ€๋‚  ๊ฒƒ์„ ์•Œ๊ธฐ ๋•Œ๋ฌธ์— ์Šค์ฝ”ํ•‘์„ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด scoper.inc.php์—์„œ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

return [
  'whitelist' => [
    // Own namespaces
    'PoPSchema\*',
    'PoP\*',
    'GraphQLByPoP\*',
    'GraphQLAPI\*',
    // Own container cache
    'PoPContainer\*',
  ],
];

๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์€ ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ์— ํ•ด๋‹นํ•˜๋ฉฐ, ์ด๊ฒƒ๋„ ์Šค์ฝ”ํ•‘๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ธ€๋กœ๋ฒŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์ง์ ‘ ProjectServiceContainer๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ PHP-Scoper๋Š” ๊ธ€๋กœ๋ฒŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ํŠน์ • ํด๋ž˜์Šค๋ฅผ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ธ๊ณต์ ์ธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค PoPContainer๋ฅผ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜๊ณ , ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋””์Šคํฌ์— ๋คํ”„ํ•  ๋•Œ ์ด ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ํ• ๋‹นํ–ˆ์Šต๋‹ˆ๋‹ค.

$dumper = new PhpDumper($containerBuilder);
file_put_contents(
  self::$cacheFile,
  $dumper->dump(
    // Save under own namespace to avoid conflicts
    array('namespace' => 'PoPContainer')
  )
);

ํŒจํ‚ค์ง€์— ๋Œ€ํ•ด, ์ผ๋ถ€๋Š” -wp๋กœ ๋๋‚˜๋Š” ๊ฒƒ(์˜ˆ: pop-schema/users-wp)์ด ์žˆ๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒƒ(์˜ˆ: graphql-by-pop/graphql-server)๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ˆˆ์น˜์ฑ„์…จ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋„ค, ๋งž์Šต๋‹ˆ๋‹ค. ์ „์ž๋Š” WordPress ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๊ณ  ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†์œผ๋ฉฐ, ํ›„์ž๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์ง€๋งŒ WordPress ์ฝ”๋“œ๋Š” ์ „ํ˜€ ํฌํ•จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ, WordPress ํŒจํ‚ค์ง€์˜ ์Šค์ฝ”ํ•‘์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.

return [
  'finders' => [
    // Scope packages under vendor/, excluding local WordPress packages
    Finder::create()
      ->files()
      ->notPath([
        // Exclude libraries ending in "-wp"
        '#getpop/[a-zA-Z0-9_-]*-wp/#',
        '#pop-schema/[a-zA-Z0-9_-]*-wp/#',
        '#graphql-by-pop/[a-zA-Z0-9_-]*-wp/#',
      ])
      ->in('vendor')
  ]
];

WordPress ํŒจํ‚ค์ง€๊ฐ€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋Š”๋ฐ ๋‹ค๋ฅธ ํŒจํ‚ค์ง€๋กœ ์ถ”์ถœํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค์–ด, ์ œ ํŒจํ‚ค์ง€ getpop/routing-wp๋Š” brain/cortex์— ์˜์กดํ•˜๋ฉฐ, ์ด๊ฒƒ์€ ํ”ผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

getpop/routing-wp๋Š” WordPress ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ ํŒจํ‚ค์ง€ ์ „์ฒด๋ฅผ ์Šค์ฝ”ํ•‘ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ , ํ•ด๋‹น ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ํŒŒ์ผ์„ ์‹๋ณ„ํ•˜๊ณ  ๊ทธ ํŒŒ์ผ๋“ค์— WordPress ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ ํŒŒ์ผ๋“ค๋งŒ ์Šค์ฝ”ํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ, Cortex/Brain์— ๋Œ€ํ•œ ์ฐธ์กฐ๋Š” 2๊ฐœ์˜ ํŒŒ์ผ์—์„œ ์ด๋ฃจ์–ด์ง€๋ฉฐ, layers/Engine/packages/routing-wp/src/Hooks/SetupCortexHookSet.php๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

namespace PoP\RoutingWP\Hooks;
 
use PoP\Hooks\AbstractHookSet;
use Brain\Cortex\Route\RouteCollectionInterface;
use Brain\Cortex\Route\RouteInterface;
use Brain\Cortex\Route\QueryRoute;
use PoP\RoutingWP\WPQueries;
use PoP\Routing\Facades\RoutingManagerFacade;
 
class SetupCortexHookSet extends AbstractHookSet
{
  protected function init()
  {
    $this->hooksAPI->addAction(
      'cortex.routes',
      [$this, 'setupCortex'],
      1
    );
  }
 
  /**
   * @param RouteCollectionInterface<RouteInterface> $routes
   */
  public function setupCortex(RouteCollectionInterface $routes): void
  {
    $routingManager = RoutingManagerFacade::getInstance();
    foreach ($routingManager->getRoutes() as $route) {
      $routes->addRoute(new QueryRoute(
        $route,
        function (array $matches) {
          return WPQueries::STANDARD_NATURE;
        }
      ));
    }
  }
}

์—ฌ๊ธฐ์„œ ์ด์ƒํ•œ ์ ์„ ๋ˆˆ์น˜์ฑ„์…จ๋‚˜์š”? ์ด๊ฒƒ์€ ํ›…์˜ ๊ตฌํ˜„์ด์ง€๋งŒ add_action์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— WordPress ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋Œ€์‹ , ์„œ๋น„์Šค HooksAPIInterface์˜ ํ•จ์ˆ˜ addAction์„ ํ˜ธ์ถœํ•˜๋ฉฐ, ์ด ์„œ๋น„์Šค๋Š” ํŒจํ‚ค์ง€ getpop/hooks-wp์˜ ํด๋ž˜์Šค HooksAPI์— ์˜ํ•ด ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋ฉฐ, ๊ฑฐ๊ธฐ์„œ๋Š” WordPress ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

namespace PoP\HooksWP;
 
use PoP\Hooks\HooksAPIInterface;
 
class HooksAPI implements HooksAPIInterface
{
  public function addAction(string $tag, callable $function_to_add, int $priority = 10, int $accepted_args = 1): void
  {
    add_action($tag, $function_to_add, $priority, $accepted_args);
  }
}

์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์—ˆ์œผ๋ฏ€๋กœ, ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ์ฐธ์กฐํ•˜๋Š” 2๊ฐœ์˜ ํŒŒ์ผ์„ ์Šค์ฝ”ํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

return [
  'finders' => [
    Finder::create()->append([
      'vendor/getpop/routing-wp/src/Component.php',
      'vendor/getpop/routing-wp/src/Hooks/SetupCortexHookSet.php',
    ])
  ]
];

์•ž์„œ ์Šค์ฝ”ํ•‘ ์„ค์ •์—๋Š” ๋ช‡ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์ง€๋งŒ, 2๊ฐœ์›”๊ฐ„์˜ ์ž‘์—… ํ›„์˜€๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ๊ฐ€ ๊ทธ ์˜๋ฏธ๋ฅผ ์ž˜ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์‹ค์ œ ์ž‘์—…์€ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ 2๊ฐœ์˜ ์„ธํŠธ๋กœ ๊น”๋”ํ•˜๊ฒŒ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ ๊ฒฝ์šฐ, ์ž‘์—…์— 2๊ฐœ์›”์ด ๊ฑธ๋ฆฐ ๊ฒƒ์€ ์„ธ๋ถ€ ์ˆ˜์ค€์ด ๊ทน๋‹จ์ ์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์€ 125๊ฐœ์˜ ํŒจํ‚ค์ง€๋กœ ๊ตฌ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ์˜ˆ์™ธ์ ์ธ ๊ฒฝ์šฐ๋กœ, ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ๊ธฐ๋ฐ˜ ์„œ๋ฒ„๋ฅผ CMS ๋น„์ข…์†์ ์œผ๋กœ ๋งŒ๋“ค์–ด ํ•ด๋‹นํ•˜๋Š” -wp ํŒจํ‚ค์ง€๋ฅผ ์žฌ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋‹ค๋ฅธ CMS/ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ตฌํ˜„์„ ์ง€์›ํ•˜๋ ค๋Š” ๋ชฉํ‘œ๊ฐ€ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

(์ด ์ „๋žต์— ๋Œ€ํ•ด์„œ๋Š” Abstracting WordPress Code To Reuse With Other CMSs: Concepts์™€ Implementation ๊ธฐ์‚ฌ์—์„œ ์ž์„ธํžˆ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.)

ํ™•์‹คํžˆ ์ƒ๋‹นํ•œ ์ž‘์—…์ด์ง€๋งŒ, ์ฝ”๋“œ์˜ ๊น”๋”ํ•จ์ด ํ–ฅ์ƒ๋˜์–ด ๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค์ฝ”ํ•‘๋ฟ๋งŒ ์•„๋‹ˆ๋ผ(์ด๊ฒƒ์€ ์ €์—๊ฒŒ ์™„์ „ํžˆ ๋†€๋ผ์šด ์ผ์ด์—ˆ๊ณ , ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํ–‰๋ณต์— ์•„์ง๋„ ๊ธฐ๋ปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค), ์˜ˆ๋ฅผ ๋“ค์–ด PHPStan๊ณผ PHPUnit์„ WordPress ์ฝ”๋“œ์™€ ๋น„-WordPress ์ฝ”๋“œ์— ๋ณ„๋„๋กœ ์‹คํ–‰ํ•˜์—ฌ ๋งŽ์€ ๊ณจ์น˜๊ฑฐ๋ฆฌ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ ์ •๋ฆฌ๋˜๋ฉด, ์„ธ์ƒ์€ ๊ฐ‘์ž๊ธฐ ํ›จ์”ฌ ๋” ๋‚˜์€ ๊ณณ์ด ๋ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ

๊ทธ๋ ‡๋‹ค๋ฉด, ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธํ• ๊นŒ์š”?

์ œ๊ฐ€ ์ƒ๊ฐํ•ด๋‚ธ ํ•ด๊ฒฐ์ฑ…์€ PHP ์ฝ”๋“œ๋ฅผ ๊ฐœ๋ฐœ์šฉ PHP 7.4์—์„œ ํ”„๋กœ๋•์…˜์šฉ 7.1๋กœ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋„๊ตฌ Rector๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•„์ด๋””์–ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์Šค์ฝ”ํ•‘ํ•œ๋‹ค
  2. ์–ด๋–ค ๊ทœ์น™์ด๋“  ์ ์šฉํ•˜์—ฌ Rector๋กœ ๋ถ„์„ํ•œ๋‹ค(์–ด๋–ค ๊ทœ์น™์ด๋“  ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค)

์Šค์ฝ”ํ•‘ ์ค‘์— ๋ฌด์–ธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ๋‹ค๋ฉด, Rector๋Š” ์ผ๋ถ€ ํด๋ž˜์Šค๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์–ด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํด๋ž˜์Šค Brain\Cortex๊ฐ€ PrefixedByPoP\Brain\Cortex๋กœ ์Šค์ฝ”ํ•‘๋˜์—ˆ๋Š”๋ฐ, ์ผ๋ถ€ ์ฐธ์กฐ๊ฐ€ ์—ฌ์ „ํžˆ Brain\Cortex๋กœ ๋‚จ์•„ ์žˆ๋‹ค๋ฉด ์ด ํด๋ž˜์Šค์˜ ์ž๋™ ๋กœ๋”ฉ์ด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ํ…Œ์ŠคํŠธ์šฉ GitHub Action์ž…๋‹ˆ๋‹ค(working-directory๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ชจ๋…ธ๋ฆฌํฌ์˜ ๋ฃจํŠธ์—์„œ ์ž‘์—…ํ•˜์ง€๋งŒ ์Šค์ฝ”ํ•‘์€ ํ”Œ๋Ÿฌ๊ทธ์ธ ํด๋”์—์„œ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค).

name: Scope Gato GraphQL tests
on:
  push:
    branches:
      - master
  pull_request: null
 
env:
  COMPOSER_ROOT_VERSION: "dev-master"
 
jobs:
  main:
    defaults:
      run:
        working-directory: layers/GraphQLAPIForWP/plugins/graphql-api-for-wp
 
    name: Scope the plugin code via PHP-Scoper, and execute tests
 
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
 
      - name: Set-up PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: 7.4
          coverage: none
        env:
          COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
      - name: Install root dependencies
        uses: "ramsey/composer-install@v1"
 
      - name: Install plugin dependencies for PROD
        run: composer install --no-dev --no-progress --no-interaction --ansi
 
      - name: Install PHP-Scoper
        run: |
          composer global config minimum-stability dev
          composer global config prefer-stable true
          composer global require humbug/php-scoper
 
      # The scoped results correspond to vendor/, so must generate them in such folder
      - name: Scope plugin into separate folder
        run: php-scoper add-prefix --output-dir ../../../../build-prefixed/vendor --ansi
 
      - name: Copy scoped code back into plugin
        run: rsync -av build-prefixed/ layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/ --quiet
        working-directory: .
 
      - name: Regenerate autoloader
        run: composer dumpautoload --optimize --classmap-authoritative --ansi
 
      - name: Run Rector on the scoped code
        run: vendor/bin/rector process --config=layers/GraphQLAPIForWP/plugins/graphql-api-for-wp/rector-test-scoping.php --ansi
        working-directory: .
 

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์ด ์ œ Rector ์„ค์ •์ž…๋‹ˆ๋‹ค.

use Rector\CodeQuality\Rector\LogicalAnd\AndAssignsToSeparateLinesRector;
use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
 
return static function (ContainerConfigurator $containerConfigurator): void {
  $services = $containerConfigurator->services();
  $services->set(AndAssignsToSeparateLinesRector::class);
  $parameters->set(Option::AUTO_IMPORT_NAMES, true);
 
  $parameters->set(Option::AUTOLOAD_PATHS, [
    __DIR__ . '/vendor/scoper-autoload.php',
    __DIR__ . '/vendor/erusev/parsedown/Parsedown.php',
    __DIR__ . '/vendor/jrfnl/php-cast-to-type/cast-to-type.php',
    __DIR__ . '/vendor/jrfnl/php-cast-to-type/class.cast-to-type.php',
  ]);
 
  // files to rector
  $parameters->set(Option::PATHS, [
    __DIR__ . '/vendor',
  ]);
 
  // files to skip
  $parameters->set(Option::SKIP, [
    // Exclude tests
    '*/tests/*',
    __DIR__ . '/vendor/nikic/fast-route/test/*',
    __DIR__ . '/vendor/psr/log/Psr/Log/Test/*',
    __DIR__ . '/vendor/symfony/service-contracts/Test/*',
  ]);
};

erusev/parsedown/Parsedown.php์™€ ๊ฐ™์€ ์ผ๋ถ€ ์˜์กด์„ฑ ํŒŒ์ผ์€ Option::AUTOLOAD_PATHS์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํŒจํ‚ค์ง€์˜ composer.json ์Šค์ฝ”ํ•‘์ด 100% ์‹ ๋ขฐํ•  ์ˆ˜ ์—†์–ด ์ž๋™ ๋กœ๋”ฉ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๊ฒฝ์šฐ, Rector๋Š” ์–ด๋–ค ํด๋ž˜์Šค์˜ ์ž๋™ ๋กœ๋”ฉ์ด ์‹คํŒจํ–ˆ๋‹ค๊ณ  ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋กœ๋ถ€ํ„ฐ ํ•ด๋‹น ํŒŒ์ผ์„ ์‹๋ณ„ํ•˜๊ณ  ์ž๋™ ๋กœ๋”ฉ ๊ฒฝ๋กœ์— ์ˆ˜๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ ํ™•์ธ

์ด๊ฒƒ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ์†Œ์Šค ์ฝ”๋“œ์ด๋ฉฐ, ์ด๊ฒƒ์ด ์Šค์ฝ”ํ•‘๋œ(PHP 7.1๋กœ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ๋œ) ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

7๊ฐ€์ง€ ์ฐจ์ด์ ์„ ์ฐพ์•„๋ณด์„ธ์š” ๐Ÿ˜. (ํžŒํŠธ๋ฅผ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. PrefixedByPoP๋ฅผ ๊ฒ€์ƒ‰ํ•ด ๋ณด์„ธ์š”.)

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์ด ์ตœ์ข… graphql-api.zip ํ”Œ๋Ÿฌ๊ทธ์ธ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ์‚ฌ์ดํŠธ์— ์„ค์น˜ํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ƒ์ž…๋‹ˆ๋‹ค. ๋„์›€์ด ๋˜์…จ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜ƒ๐Ÿ’ช๐Ÿš€


๋‰ด์Šค๋ ˆํ„ฐ ๊ตฌ๋…ํ•˜๊ธฐ

Gato GraphQL์˜ ๋ชจ๋“  ์—…๋ฐ์ดํŠธ๋ฅผ ๋†“์น˜์ง€ ๋งˆ์„ธ์š”.