1+ <?php
2+
3+ namespace Saritasa \Laravel \Controllers \Api ;
4+
5+ use Saritasa \Exceptions \ConfigurationException ;
6+ use Dingo \Api \Routing \Router ;
7+
8+ /**
9+ * Wrapper for Dingo router, adds concise methods for API URLs registration.
10+ * @method void get(string $resource, string $controller, string $action = null, string $route = null) Add POST route
11+ * @method void post(string $resource, string $controller, string $action = null, string $route = null) Add POST route
12+ * @method void patch(string $resource, string $controller, string $action = null, string $route = null) Add POST route
13+ * @method void put(string $resource, string $controller, string $action = null, string $route = null) Add POST route
14+ * @method void delete(string $resource, string $controller, string $action = null, string $route = null) Add POST route
15+ */
16+ class ApiResourceRegistrar
17+ {
18+ /**
19+ * @var Router
20+ */
21+ private $ api ;
22+
23+ private $ default = [
24+ 'index ' => ['verb ' => 'get ' , 'route ' => '' ],
25+ 'create ' => ['verb ' => 'post ' , 'route ' => '' ],
26+ 'show ' => ['verb ' => 'get ' , 'route ' => '/{id} ' ],
27+ 'update ' => ['verb ' => 'put ' , 'route ' => '/{id} ' ],
28+ 'destroy ' => ['verb ' => 'delete ' , 'route ' => '/{id} ' ]
29+ ];
30+
31+ const VERBS = ['get ' , 'post ' , 'put ' , 'patch ' , 'delete ' ];
32+
33+ public function __construct (Router $ api )
34+ {
35+ $ this ->api = $ api ;
36+ }
37+
38+ /**
39+ * Registers controller methods
40+ *
41+ * index - as GET /resourceName
42+ * create - as POST /resourceName
43+ * show - as GET /resourceName/{id}
44+ * update - as PUT /resourceName/{id}
45+ * destroy - as DELETE /resourceName/{id}
46+ *
47+ * @param string $resourceName
48+ * @param string $controller
49+ * @param array $options
50+ */
51+ public function resource (string $ resourceName , string $ controller , array $ options = [])
52+ {
53+ $ routes = [];
54+ if (!$ options || !count ($ options )) {
55+ $ routes = $ this ->default ;
56+ } else if (isset ($ options ['only ' ])) {
57+ $ routes = array_intersect_key ($ this ->default , $ this ->asArray ($ options ['only ' ]));
58+ } else if (isset ($ options ['except ' ])) {
59+ $ routes = array_diff_key ($ this ->default , $ this ->asArray ($ options ['except ' ]));
60+ }
61+
62+ foreach (static ::VERBS as $ verb ) {
63+ if (isset ($ options [$ verb ])) {
64+ $ actions = $ this ->asArray ($ options [$ verb ]);
65+ if (!is_array ($ actions )) {
66+ $ t = gettype ($ actions );
67+ throw new \InvalidArgumentException ("\$options[' $ verb'] must contain string or array. $ t was given " );
68+ }
69+
70+ foreach ($ actions as $ action => $ i ) {
71+ $ routes [$ action ] = ['verb ' => $ verb , 'route ' => '/ ' .$ action ];
72+ }
73+ }
74+ }
75+
76+ foreach ($ routes as $ action => $ opt ) {
77+ $ verb = $ opt ['verb ' ];
78+ $ this ->api ->$ verb ($ resourceName .$ opt ['route ' ], [
79+ 'as ' => $ resourceName .'. ' .$ action ,
80+ 'uses ' => $ controller .'@ ' .$ action
81+ ]);
82+ }
83+ }
84+
85+ public function __call ($ name , $ arguments )
86+ {
87+ if (in_array ($ name , static ::VERBS )) {
88+ array_splice ($ arguments , 0 , 0 , [$ name ]);
89+ return call_user_func_array ([$ this , 'action ' ], $ arguments );
90+ }
91+ throw new ConfigurationException ("Unknown HTTP verb $ name used for route $ arguments [0 ]" );
92+ }
93+
94+ /**
95+ * @param string $verb - one of GET / POST / PUT / DELETE
96+ * @param string $path - URL path
97+ * @param string $controller Class, containing action method
98+ * @param string|null $action method, which will be executed on route hit
99+ * @param string|null $route - route name
100+ * @return mixed
101+ */
102+ private function action (string $ verb , string $ path , string $ controller , string $ action = null , string $ route = null )
103+ {
104+ $ pos = strrpos ($ path , '/ ' , -1 );
105+ $ pathLastSegment = $ pos ? substr ($ path , $ pos +1 ) : $ path ;
106+
107+ if (!$ action ) {
108+ $ action = $ pathLastSegment ;
109+ }
110+ if (!$ route ) {
111+ $ route = strtolower (str_replace ('/ ' , '. ' , $ path ));
112+ // Small piece of magic: make auto-named routes look nicer
113+ if ($ pathLastSegment != $ action ) {
114+ if (strrpos ($ route , '. ' .$ pathLastSegment , -1 ) === false ) {
115+ $ route = "$ route. $ action " ;
116+ } else {
117+ $ route = str_replace ('. ' . $ pathLastSegment , '. ' . $ action , $ route );
118+ }
119+ }
120+ $ route = strtolower ($ route );
121+ }
122+ return $ this ->api ->$ verb ($ path ?: $ action , ['uses ' => $ controller .'@ ' .$ action , 'as ' => $ route ]);
123+ }
124+
125+ private function asArray ($ value ): array
126+ {
127+ if (is_array ($ value )) {
128+ return $ value ;
129+ }
130+ if (is_string ($ value )) {
131+ $ keys = explode (', ' , $ value );
132+ return array_flip ($ keys );
133+ }
134+ return null ;
135+ }
136+ }
0 commit comments