| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace Backpack\CRUD\app\Http\Controllers\Operations; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use Illuminate\Support\Facades\Route; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use Illuminate\Support\Str; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 8 |  |  | trait FetchOperation | 
            
                                                                        
                            
            
                                    
            
            
                | 9 |  |  | { | 
            
                                                                        
                            
            
                                    
            
            
                | 10 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 11 |  |  |      * Define which routes are needed for this operation. | 
            
                                                                        
                            
            
                                    
            
            
                | 12 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 13 |  |  |      * @param  string  $segment  Name of the current entity (singular). Used as first URL segment. | 
            
                                                                        
                            
            
                                    
            
            
                | 14 |  |  |      * @param  string  $routeName  Prefix of the route name. | 
            
                                                                        
                            
            
                                    
            
            
                | 15 |  |  |      * @param  string  $controller  Name of the current CrudController. | 
            
                                                                        
                            
            
                                    
            
            
                | 16 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     protected function setupFetchOperationRoutes($segment, $routeName, $controller) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |         // get all method names on the current model that start with "fetch" (ex: fetchCategory) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |         // if a method that looks like that is present, it means we need to add the routes that fetch that entity | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         preg_match_all('/(?<=^|;)fetch([^;]+?)(;|$)/', implode(';', get_class_methods($this)), $matches); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         if (count($matches[1])) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |             foreach ($matches[1] as $methodName) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |                 Route::post($segment.'/fetch/'.Str::kebab($methodName), [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |                     'as'        => $segment.'.fetch'.Str::studly($methodName), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |                     'uses'      => $controller.'@fetch'.$methodName, | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 28 |  |  |                     'operation' => 'FetchOperation', | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |                 ]); | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |             } | 
            
                                                                        
                            
            
                                    
            
            
                | 31 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 32 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |      * Gets items from database and returns to selects. | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 37 |  |  |      * @param  string|array  $arg | 
            
                                                                        
                            
            
                                    
            
            
                | 38 |  |  |      * @return \Illuminate\Http\JsonResponse|Illuminate\Database\Eloquent\Collection|Illuminate\Pagination\LengthAwarePaginator | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                        
                            
            
                                    
            
            
                | 39 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |     private function fetch($arg) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |         // get the actual words that were used to search for an item (the search term / search string) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         $search_string = request()->input('q') ?? false; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |         // if the Class was passed as the sole argument, use that as the configured Model | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         // otherwise assume the arguments are actually the configuration array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         $config = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         if (! is_array($arg)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |             if (! class_exists($arg)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |                 return response()->json(['error' => 'Class: '.$arg.' does not exists'], 500); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |             $config['model'] = $arg; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |             $config = $arg; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         $model_instance = new $config['model']; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |         // set configuration defaults | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |         $config['paginate'] = isset($config['paginate']) ? $config['paginate'] : 10; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |         $config['searchable_attributes'] = $config['searchable_attributes'] ?? $model_instance->identifiableAttribute(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         $config['query'] = isset($config['query']) && is_callable($config['query']) ? $config['query']($model_instance) : $model_instance; // if a closure that has been passed as "query", use the closure - otherwise use the model | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         // FetchOperation sends an empty query to retrieve the default entry for select when field is not nullable. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         // Also sends an empty query in case we want to load all entities to emulate non-ajax fields | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |         // when using InlineCreate. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         if ($search_string === false) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |             return ($config['paginate'] !== false) ? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |             $config['query']->paginate($config['paginate']) : | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |             $config['query']->get(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |         $textColumnTypes = ['string', 'json_string', 'text', 'longText', 'json_array', 'json']; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         // if the query builder brings any where clause already defined by the user we must | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |         // ensure that the where prevails and we should only use our search as a complement to the query constraints. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         // e.g user want only the active products, so in fetch they would return something like: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         // .... 'query' => function($model) { return $model->where('active', 1); } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         // So it reads: SELECT ... WHERE active = 1 AND (XXX = x OR YYY = y) and not SELECT ... WHERE active = 1 AND XXX = x OR YYY = y; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |         if (! empty($config['query']->getQuery()->wheres)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |             $config['query'] = $config['query']->where(function ($query) use ($model_instance, $config, $search_string, $textColumnTypes) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |                 foreach ((array) $config['searchable_attributes'] as $k => $searchColumn) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                     $operation = ($k == 0) ? 'where' : 'orWhere'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |                     $columnType = $model_instance->getColumnType($searchColumn); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |                     if (in_array($columnType, $textColumnTypes)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |                         $tempQuery = $query->{$operation}($searchColumn, 'LIKE', '%'.$search_string.'%'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |                     } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |                         $tempQuery = $query->{$operation}($searchColumn, $search_string); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |                     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |                 } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |                 // If developer provide an empty searchable_attributes array it means they don't want us to search | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |                 // in any specific column, or try to guess the column from model identifiableAttribute. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |                 // In that scenario we will not have any $tempQuery here, so we just return the query, is up to the developer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |                 // to do their own search. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |                 return $tempQuery ?? $query; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |             }); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |             foreach ((array) $config['searchable_attributes'] as $k => $searchColumn) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |                 $operation = ($k == 0) ? 'where' : 'orWhere'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |                 $columnType = $model_instance->getColumnType($searchColumn); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |                 if (in_array($columnType, $textColumnTypes)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |                     $config['query'] = $config['query']->{$operation}($searchColumn, 'LIKE', '%'.$search_string.'%'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |                 } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |                     $config['query'] = $config['query']->{$operation}($searchColumn, $search_string); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |                 } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |         // return the results with or without pagination | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |         return ($config['paginate'] !== false) ? | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |                     $config['query']->paginate($config['paginate']) : | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 116 |  |  |                     $config['query']->get(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 118 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 119 |  |  |  |