├── .editorconfig ├── .idea ├── encodings.xml ├── modules.xml ├── php.xml ├── starter-framework.iml └── vcs.xml ├── .styleci.yml ├── CHANGELOG.md ├── CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json └── src └── Someline ├── Api ├── Auth │ └── Provider │ │ ├── OAuth2.php │ │ └── Passport.php ├── Foundation │ └── Validation │ │ └── ValidatesRequests.php └── Middleware │ ├── ApiAccessMiddleware.php │ ├── ApiAuthMiddleware.php │ └── AutoRenewJwtToken.php ├── Auth └── AuthUserHelpers.php ├── Base ├── Api │ └── Controllers │ │ └── Controller.php ├── Events │ └── Event.php ├── Http │ └── Controllers │ │ └── Controller.php ├── Models │ └── BaseModel.php ├── Policies │ └── Policy.php ├── Presenters │ └── Presenter.php ├── Repositories │ ├── Eloquent │ │ └── Repository.php │ └── Interfaces │ │ └── RepositoryInterface.php └── Transformers │ └── Transformer.php ├── Foundation └── helpers.php ├── Model ├── Basic │ ├── CountryModel.php │ └── PhoneNumberModel.php ├── Foundation │ └── User.php ├── Interfaces │ └── BaseModelEventsInterface.php ├── Observers │ └── BaseModelObserver.php └── Traits │ └── BaseModelEvents.php ├── Presenters └── BasicPresenter.php ├── Repositories ├── Criteria │ ├── AuthUserCriteria.php │ ├── OwnerUsersCriteria.php │ └── RequestCriteria.php └── PresenterRepository.php ├── Repository ├── Generators │ ├── BindingsGenerator.php │ ├── Commands │ │ ├── BindingsCommand.php │ │ ├── CommandBase.php │ │ ├── ControllerCommand.php │ │ ├── CriteriaCommand.php │ │ ├── EntityCommand.php │ │ ├── PresenterCommand.php │ │ ├── RepositoryCommand.php │ │ ├── TransformerCommand.php │ │ └── ValidatorCommand.php │ ├── ControllerGenerator.php │ ├── CriteriaGenerator.php │ ├── FileAlreadyExistsException.php │ ├── Generator.php │ ├── MigrationGenerator.php │ ├── Migrations │ │ ├── NameParser.php │ │ ├── RulesParser.php │ │ └── SchemaParser.php │ ├── ModelGenerator.php │ ├── PresenterGenerator.php │ ├── RepositoryEloquentGenerator.php │ ├── RepositoryInterfaceGenerator.php │ ├── Stub.php │ ├── Stubs │ │ ├── bindings │ │ │ └── bindings.stub │ │ ├── controller │ │ │ └── controller.stub │ │ ├── criteria │ │ │ └── criteria.stub │ │ ├── migration │ │ │ ├── change.stub │ │ │ └── create.stub │ │ ├── model.stub │ │ ├── presenter │ │ │ └── presenter.stub │ │ ├── repository │ │ │ ├── eloquent.stub │ │ │ └── interface.stub │ │ ├── seed.stub │ │ ├── transformer │ │ │ └── transformer.stub │ │ └── validator │ │ │ └── validator.stub │ ├── TransformerGenerator.php │ └── ValidatorGenerator.php └── Providers │ └── RepositoryServiceProvider.php ├── Support ├── Controllers │ └── LocaleController.php └── Middleware │ └── LocaleMiddleware.php └── Transformers └── BasicTransformer.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/starter-framework.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `starter-framework` will be documented in this file. 4 | 5 | Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. 6 | 7 | ## NEXT - YYYY-MM-DD 8 | 9 | ### Added 10 | - Nothing 11 | 12 | ### Deprecated 13 | - Nothing 14 | 15 | ### Fixed 16 | - Nothing 17 | 18 | ### Removed 19 | - Nothing 20 | 21 | ### Security 22 | - Nothing 23 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | * The use of sexualized language or imagery 10 | * Personal attacks 11 | * Trolling or insulting/derogatory comments 12 | * Public or private harassment 13 | * Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | * Other unethical or unprofessional conduct. 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/someline/starter-framework). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ composer test 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Libern Lin 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Someline Starter Framework (Kernel) 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![Software License][ico-license]](LICENSE.md) 5 | [![Total Downloads][ico-downloads]][link-downloads] 6 | 7 | The [Someline Starter](https://starter.someline.com/) Framework. 8 | 9 | ## Change log 10 | 11 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 12 | 13 | ## Contributing 14 | 15 | Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details. 16 | 17 | ## Security 18 | 19 | If you discover any security related issues, please email libernlin@gmail.com instead of using the issue tracker. 20 | 21 | ## Credits 22 | 23 | - [Libern Lin][link-author] 24 | - [All Contributors][link-contributors] 25 | 26 | ## License 27 | 28 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 29 | 30 | [ico-version]: https://img.shields.io/packagist/v/someline/starter-framework.svg?style=flat-square 31 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 32 | [ico-travis]: https://img.shields.io/travis/someline/starter-framework/master.svg?style=flat-square 33 | [ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/someline/starter-framework.svg?style=flat-square 34 | [ico-code-quality]: https://img.shields.io/scrutinizer/g/someline/starter-framework.svg?style=flat-square 35 | [ico-downloads]: https://img.shields.io/packagist/dt/someline/starter-framework.svg?style=flat-square 36 | 37 | [link-packagist]: https://packagist.org/packages/someline/starter-framework 38 | [link-travis]: https://travis-ci.org/someline/starter-framework 39 | [link-scrutinizer]: https://scrutinizer-ci.com/g/someline/starter-framework/code-structure 40 | [link-code-quality]: https://scrutinizer-ci.com/g/someline/starter-framework 41 | [link-downloads]: https://packagist.org/packages/someline/starter-framework 42 | [link-author]: https://github.com/libern 43 | [link-contributors]: ../../contributors 44 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "someline/starter-framework", 3 | "type": "framework", 4 | "description": "The Someline Starter Framework.", 5 | "keywords": [ 6 | "someline", 7 | "starter-framework" 8 | ], 9 | "homepage": "https://github.com/someline/starter-framework", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Libern Lin", 14 | "email": "libernlin@gmail.com", 15 | "homepage": "https://www.someline.com/", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^7.1.3", 21 | "ext-pdo_sqlite": "*", 22 | "fideloper/proxy": "^4.0", 23 | "laravel/framework": "5.8.*|6.0.*", 24 | "laravel/tinker": "^1.0", 25 | "predis/predis": "~1.1", 26 | "doctrine/dbal": "~2.9", 27 | "itsgoingd/clockwork": "^4.0", 28 | "guzzlehttp/guzzle": "~6.3", 29 | "lukasoppermann/http-status": "^2.0", 30 | "prettus/l5-repository": "^2.6", 31 | "prettus/laravel-validation": "1.1.*", 32 | "intervention/image": "^2.4", 33 | "intervention/imagecache": "^2.3", 34 | "barryvdh/laravel-ide-helper": "^2.6", 35 | "someline/rest-api-client": "1.2.*", 36 | "someline/someline-image": "2.3.*", 37 | "mcamara/laravel-localization": "1.3.*", 38 | "laravel/passport": "^7.2", 39 | "monarobase/country-list": "^2.1", 40 | "libern/timezone": "^1.0", 41 | "giggsey/libphonenumber-for-php": "~8.10", 42 | "torann/geoip": "1.0.*" 43 | }, 44 | "require-dev": { 45 | "phpunit/phpunit": "~4.0||~5.0||~6.0||~7.0", 46 | "scrutinizer/ocular": "~1.1", 47 | "squizlabs/php_codesniffer": "~2.3" 48 | }, 49 | "autoload": { 50 | "files": [ 51 | "src/Someline/Foundation/helpers.php" 52 | ], 53 | "psr-4": { 54 | "Someline\\": "src/Someline" 55 | } 56 | }, 57 | "autoload-dev": { 58 | "psr-4": { 59 | "Someline\\Test\\": "tests" 60 | } 61 | }, 62 | "scripts": { 63 | "test": "phpunit", 64 | "format": "phpcbf --standard=psr2 src/" 65 | }, 66 | "extra": { 67 | "branch-alias": { 68 | "dev-master": "1.0-dev" 69 | }, 70 | "laravel": { 71 | "providers": [ 72 | "Someline\\Repository\\Providers\\RepositoryServiceProvider" 73 | ] 74 | } 75 | }, 76 | "minimum-stability": "dev" 77 | } 78 | -------------------------------------------------------------------------------- /src/Someline/Api/Auth/Provider/OAuth2.php: -------------------------------------------------------------------------------- 1 | resource; 19 | } 20 | 21 | /** 22 | * @return \League\OAuth2\Server\Entity\AccessTokenEntity 23 | */ 24 | public function getAccessToken() 25 | { 26 | return $this->resource->getAccessToken(); 27 | } 28 | 29 | 30 | /** 31 | * @return \League\OAuth2\Server\Entity\SessionEntity 32 | */ 33 | public function getSession() 34 | { 35 | return $this->getAccessToken()->getSession(); 36 | } 37 | 38 | /** 39 | * Get the resource owner ID of the current request. 40 | * 41 | * @return string 42 | */ 43 | public function getResourceOwnerId() 44 | { 45 | return $this->getSession()->getOwnerId(); 46 | } 47 | 48 | /** 49 | * Get the resource owner type of the current request (client or user). 50 | * 51 | * @return string 52 | */ 53 | public function getResourceOwnerType() 54 | { 55 | return $this->getSession()->getOwnerType(); 56 | } 57 | 58 | /** 59 | * Get the client of the current request. 60 | * 61 | * @return \League\OAuth2\Server\Entity\ClientEntity 62 | */ 63 | public function getClient() 64 | { 65 | return $this->getSession()->getClient(); 66 | } 67 | 68 | /** 69 | * Get the client id of the current request. 70 | * 71 | * @return string 72 | */ 73 | public function getClientId() 74 | { 75 | return $this->getClient()->getId(); 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/Someline/Api/Auth/Provider/Passport.php: -------------------------------------------------------------------------------- 1 | auth = $auth->guard($this->guard); 40 | } 41 | 42 | /** 43 | * Authenticate request with a Illuminate Guard. 44 | * 45 | * @param \Illuminate\Http\Request $request 46 | * @param \Dingo\Api\Routing\Route $route 47 | * 48 | * @return mixed 49 | */ 50 | public function authenticate(Request $request, Route $route) 51 | { 52 | if ( ! $user = $this->auth->user()) { 53 | throw new UnauthorizedHttpException(null, 'Unauthenticated.'); 54 | } 55 | 56 | return $user; 57 | } 58 | 59 | /** 60 | * Get the providers authorization method. 61 | * 62 | * @return string 63 | */ 64 | public function getAuthorizationMethod() 65 | { 66 | return 'Bearer'; 67 | } 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/Someline/Api/Foundation/Validation/ValidatesRequests.php: -------------------------------------------------------------------------------- 1 | getValidationFactory()->make($request->all(), $validator); 34 | } 35 | 36 | if ($validator->fails()) { 37 | $this->throwValidationException($request, $validator); 38 | } 39 | } 40 | 41 | /** 42 | * Validate the given request with the given rules. 43 | * 44 | * @param \Illuminate\Http\Request $request 45 | * @param array $rules 46 | * @param array $messages 47 | * @param array $customAttributes 48 | * @return void 49 | */ 50 | public function validate(Request $request, array $rules, array $messages = [], array $customAttributes = []) 51 | { 52 | $validator = $this->getValidationFactory()->make($request->all(), $rules, $messages, $customAttributes); 53 | 54 | if ($validator->fails()) { 55 | $this->throwValidationException($request, $validator); 56 | } 57 | } 58 | 59 | /** 60 | * Validate the given request with the given rules. 61 | * 62 | * @param \Illuminate\Http\Request $request 63 | * @param array $data 64 | * @param array $rules 65 | * @param array $messages 66 | * @param array $customAttributes 67 | */ 68 | public function validateData(Request $request, array $data, array $rules, array $messages = [], array $customAttributes = []) 69 | { 70 | $validator = $this->getValidationFactory()->make($data, $rules, $messages, $customAttributes); 71 | 72 | if ($validator->fails()) { 73 | $this->throwValidationException($request, $validator); 74 | } 75 | } 76 | 77 | /** 78 | * Validate the given request with the given rules. 79 | * 80 | * @param string $errorBag 81 | * @param \Illuminate\Http\Request $request 82 | * @param array $rules 83 | * @param array $messages 84 | * @param array $customAttributes 85 | * @return void 86 | * 87 | * @throws \Illuminate\Foundation\Validation\ValidationException 88 | */ 89 | public function validateWithBag($errorBag, Request $request, array $rules, array $messages = [], array $customAttributes = []) 90 | { 91 | $this->withErrorBag($errorBag, function () use ($request, $rules, $messages, $customAttributes) { 92 | $this->validate($request, $rules, $messages, $customAttributes); 93 | }); 94 | } 95 | 96 | /** 97 | * Throw the failed validation exception. 98 | * 99 | * @param \Illuminate\Http\Request $request 100 | * @param \Illuminate\Contracts\Validation\Validator $validator 101 | * @return void 102 | * 103 | * @throws \Illuminate\Foundation\Validation\ValidationException 104 | */ 105 | protected function throwValidationException(Request $request, $validator) 106 | { 107 | throw new ResourceException($validator->errors()->first(), $validator->errors()); 108 | // throw new ValidationException($validator, $this->buildFailedValidationResponse( 109 | // $request, $this->formatValidationErrors($validator) 110 | // )); 111 | } 112 | 113 | /** 114 | * Create the response for when a request fails validation. 115 | * 116 | * @param \Illuminate\Http\Request $request 117 | * @param array $errors 118 | * @return \Illuminate\Http\Response 119 | */ 120 | protected function buildFailedValidationResponse(Request $request, array $errors) 121 | { 122 | if (($request->ajax() && !$request->pjax()) || $request->wantsJson()) { 123 | return new JsonResponse($errors, 422); 124 | } 125 | 126 | return redirect()->to($this->getRedirectUrl()) 127 | ->withInput($request->input()) 128 | ->withErrors($errors, $this->errorBag()); 129 | } 130 | 131 | /** 132 | * Format the validation errors to be returned. 133 | * 134 | * @param \Illuminate\Contracts\Validation\Validator $validator 135 | * @return array 136 | */ 137 | protected function formatValidationErrors(Validator $validator) 138 | { 139 | return $validator->errors()->getMessages(); 140 | } 141 | 142 | /** 143 | * Get the URL we should redirect to. 144 | * 145 | * @return string 146 | */ 147 | protected function getRedirectUrl() 148 | { 149 | return app(UrlGenerator::class)->previous(); 150 | } 151 | 152 | /** 153 | * Get a validation factory instance. 154 | * 155 | * @return \Illuminate\Contracts\Validation\Factory 156 | */ 157 | protected function getValidationFactory() 158 | { 159 | return app(Factory::class); 160 | } 161 | 162 | /** 163 | * Execute a Closure within with a given error bag set as the default bag. 164 | * 165 | * @param string $errorBag 166 | * @param callable $callback 167 | * @return void 168 | */ 169 | protected function withErrorBag($errorBag, callable $callback) 170 | { 171 | $this->validatesRequestErrorBag = $errorBag; 172 | 173 | call_user_func($callback); 174 | 175 | $this->validatesRequestErrorBag = null; 176 | } 177 | 178 | /** 179 | * Get the key to be used for the view error bag. 180 | * 181 | * @return string 182 | */ 183 | protected function errorBag() 184 | { 185 | return $this->validatesRequestErrorBag ?: 'default'; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/Someline/Api/Middleware/ApiAccessMiddleware.php: -------------------------------------------------------------------------------- 1 | exception) && $response->exception) { 37 | throw $response->exception; 38 | } 39 | 40 | return $response; 41 | } catch (OAuthException $e) { 42 | $message = env('API_DEBUG') ? $e->getMessage() : null; 43 | throw new HttpException($e->httpStatusCode, $message, $e, $e->getHttpHeaders()); 44 | } catch (HttpResponseException $e) { 45 | $message = env('API_DEBUG') ? $e->getMessage() : null; 46 | throw new HttpException($e->getResponse()->getStatusCode(), $message, $e); 47 | } catch (AuthenticationException $e) { 48 | throw new UnauthorizedHttpException(null, $e->getMessage(), $e); 49 | } catch (ValidatorException $e) { 50 | $messageBag = $e->getMessageBag(); 51 | throw new ResourceException($messageBag->first(), $messageBag->all()); 52 | } catch (ModelNotFoundException $e) { 53 | throw new NotFoundHttpException('No results found.'); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Someline/Api/Middleware/ApiAuthMiddleware.php: -------------------------------------------------------------------------------- 1 | router = $router; 43 | $this->auth = $auth; 44 | } 45 | 46 | /** 47 | * Perform authentication before a request is executed. 48 | * 49 | * @param \Illuminate\Http\Request $request 50 | * @param \Closure $next 51 | * @param $grant 52 | * 53 | * @return mixed 54 | * @throws AccessDeniedException 55 | */ 56 | public function handle($request, Closure $next, $grant = null) 57 | { 58 | $route = $this->router->getCurrentRoute(); 59 | 60 | /** 61 | * FOR (Internal API requests) 62 | * @note GRANT(user) will always be able to access routes that are protected by: GRANT(client) 63 | * 64 | * For OAuth grants from password (i.e. Resource Owner: user) 65 | * @Auth will only check once, because user exists in auth afterwards 66 | * 67 | * For OAuth grants from client_credentials (i.e. Resource Owner: client) 68 | * @Auth will always check, because user is never exists in auth 69 | */ 70 | if (!$this->auth->check(false)) { 71 | $this->auth->authenticate($route->getAuthenticationProviders()); 72 | 73 | $provider = $this->auth->getProviderUsed(); 74 | 75 | /** @var OAuth2 $provider */ 76 | if ($provider instanceof OAuth2) { 77 | // check oauth grant type 78 | if (!is_null($grant) && $provider->getResourceOwnerType() !== $grant) { 79 | throw new AccessDeniedException(); 80 | } 81 | } 82 | 83 | // login user through Auth 84 | $user = $this->auth->getUser(); 85 | if ($user instanceof User) { 86 | \Auth::login($user); 87 | 88 | event(new UserLoggedInEvent($user)); 89 | } 90 | } 91 | 92 | return $next($request); 93 | } 94 | } -------------------------------------------------------------------------------- /src/Someline/Api/Middleware/AutoRenewJwtToken.php: -------------------------------------------------------------------------------- 1 | auth->setRequest($request)->getToken()) { 23 | // valid for refresh 24 | if (is_jwt_token_valid_for_refresh($token)) { 25 | $newToken = refresh_jwt_token(); 26 | if (!empty($newToken)) { 27 | // send the refreshed token back to the client 28 | $response->headers->set('Authorization', $newToken); 29 | } 30 | } 31 | } 32 | 33 | return $response; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Someline/Auth/AuthUserHelpers.php: -------------------------------------------------------------------------------- 1 | getAuthUser()->getUserId(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/Someline/Base/Api/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | getKey(); 77 | // } 78 | 79 | /** 80 | * Get current auth user 81 | * 82 | * @return User|null 83 | */ 84 | public function getAuthUser() 85 | { 86 | $user = null; 87 | if ($this->api_auth()->check()) { 88 | $user = $this->api_auth()->user(); 89 | } else if (\Auth::check()) { 90 | $user = \Auth::user(); 91 | } 92 | return $user; 93 | } 94 | 95 | /** 96 | * Get current auth user_id 97 | * 98 | * @return mixed|null 99 | */ 100 | public function getAuthUserId() 101 | { 102 | $user_id = null; 103 | $user = $this->getAuthUser(); 104 | if ($user) { 105 | $user_id = $user->user_id; 106 | } 107 | return $user_id; 108 | } 109 | 110 | /** 111 | * Get current model's user_id 112 | * 113 | * @return mixed|null 114 | */ 115 | public function getUserId() 116 | { 117 | return $this->user_id; 118 | } 119 | 120 | /** 121 | * Update the creation and update ips. 122 | * 123 | * @return void 124 | */ 125 | protected function updateIps() 126 | { 127 | $ip = smart_get_client_ip(); 128 | 129 | if (!$this->isDirty('updated_ip')) { 130 | $this->updated_ip = $ip; 131 | } 132 | 133 | if (!$this->exists && !$this->isDirty('created_ip')) { 134 | $this->created_ip = $ip; 135 | } 136 | } 137 | 138 | /** 139 | * Update the creation and update by users. 140 | * 141 | * @return void 142 | */ 143 | protected function updateUsers() 144 | { 145 | $user_id = $this->getAuthUserId(); 146 | if (!$this->validUserId($user_id)) { 147 | return; 148 | } 149 | 150 | if (!$this->isDirty('updated_by')) { 151 | $this->updated_by = $user_id; 152 | } 153 | 154 | if (!$this->exists && !$this->isDirty('created_by')) { 155 | $this->created_by = $user_id; 156 | } 157 | } 158 | 159 | /** 160 | * @return bool 161 | */ 162 | public function isAuthUserOwner(): bool 163 | { 164 | return $this->getAuthUserId() == $this->getUserId(); 165 | } 166 | 167 | /** 168 | * @return Carbon 169 | */ 170 | public function getNowTime() 171 | { 172 | return Carbon::now(app_timezone()); 173 | } 174 | 175 | /** 176 | * @return Carbon 177 | */ 178 | public function getNowUTCTime() 179 | { 180 | return Carbon::now('UTC'); 181 | } 182 | 183 | /** 184 | * @return Carbon 185 | */ 186 | public function getNowAuthUserTime() 187 | { 188 | return Carbon::now($this->getAuthUserDateTimezone()); 189 | } 190 | 191 | /** 192 | * @return User|null 193 | */ 194 | public function getUser() 195 | { 196 | return $this->user; 197 | } 198 | 199 | /** 200 | * @return User|null 201 | */ 202 | public function getRelatedUser() 203 | { 204 | return $this->related_user; 205 | } 206 | 207 | /** 208 | * Set Model Presenter 209 | * @return $this 210 | * @throws \Exception 211 | */ 212 | public function setModelPresenter() 213 | { 214 | $this->setPresenter(new ModelFractalPresenter()); 215 | return $this; 216 | } 217 | 218 | /** 219 | * Return a timezone for all Datetime objects 220 | * 221 | * @return mixed 222 | */ 223 | public function getAuthUserDateTimezone() 224 | { 225 | $user = $this->getAuthUser(); 226 | if ($user && !empty($user->timezone)) { 227 | return $user->timezone; 228 | } else { 229 | return app_timezone(); 230 | } 231 | } 232 | 233 | /** 234 | * Set a given attribute on the model. 235 | * 236 | * 237 | * @param string $key 238 | * @param mixed $value 239 | * @return $this 240 | */ 241 | public function setAttribute($key, $value) 242 | { 243 | 244 | if ($this->timestamp_always_save_in_utc) { 245 | // set to UTC only if Carbon 246 | if ($value instanceof Carbon) { 247 | $value->setTimezone('UTC'); 248 | } 249 | } 250 | 251 | return parent::setAttribute($key, $value); 252 | } 253 | 254 | /** 255 | * Get a plain attribute (not a relationship). 256 | * 257 | * @param string $key 258 | * @return mixed 259 | */ 260 | public function getAttributeValue($key) 261 | { 262 | $value = parent::getAttributeValue($key); 263 | 264 | if ($value instanceof Carbon && $this->timestamp_get_with_user_timezone) { 265 | $value->setTimezone($this->getAuthUserDateTimezone()); 266 | } 267 | 268 | return $value; 269 | } 270 | 271 | /** 272 | * Prepare a date for array / JSON serialization. 273 | * 274 | * @param \DateTimeInterface $date 275 | * @return string 276 | */ 277 | protected function serializeDate(\DateTimeInterface $date) 278 | { 279 | if ($date instanceof Carbon && $this->timestamp_get_with_user_timezone) { 280 | $date->setTimezone($this->getAuthUserDateTimezone()); 281 | } 282 | return $date->format($this->getDateFormat()); 283 | } 284 | 285 | /** 286 | * @return mixed|Carbon 287 | */ 288 | public function getCreatedAt() 289 | { 290 | return $this->created_at; 291 | } 292 | 293 | /** 294 | * @return mixed|Carbon 295 | */ 296 | public function getUpdatedAt() 297 | { 298 | return $this->updated_at; 299 | } 300 | 301 | } -------------------------------------------------------------------------------- /src/Someline/Base/Policies/Policy.php: -------------------------------------------------------------------------------- 1 | getUserId() == $user->getUserId(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Someline/Base/Presenters/Presenter.php: -------------------------------------------------------------------------------- 1 | resource = $this->transformCollection($data); 35 | } elseif ($data instanceof AbstractPaginator) { 36 | $this->resource = $this->transformPaginator($data); 37 | } else { 38 | $this->resource = $this->transformItem($data); 39 | } 40 | 41 | // set meta 42 | $this->resource->setMeta($this->meta); 43 | 44 | return $this->fractal->createData($this->resource)->toArray(); 45 | } 46 | 47 | /** 48 | * @param array $meta 49 | */ 50 | public function setMeta(array $meta) 51 | { 52 | $this->meta = $meta; 53 | } 54 | } -------------------------------------------------------------------------------- /src/Someline/Base/Repositories/Eloquent/Repository.php: -------------------------------------------------------------------------------- 1 | pushCriteria(new AuthUserCriteria()); 41 | return $this; 42 | } 43 | 44 | public function byUsers($userIds) 45 | { 46 | $this->pushCriteria(new OwnerUsersCriteria($userIds)); 47 | return $this; 48 | } 49 | 50 | public function authUserId() 51 | { 52 | return current_auth_user()->user_id; 53 | } 54 | 55 | public function validateCreate(array $attributes) 56 | { 57 | if (!is_null($this->validator)) { 58 | $this->validator->with($attributes) 59 | ->passesOrFail(ValidatorInterface::RULE_CREATE); 60 | } 61 | } 62 | 63 | public function validateUpdate(array $attributes) 64 | { 65 | if (!is_null($this->validator)) { 66 | $this->validator->with($attributes) 67 | ->passesOrFail(ValidatorInterface::RULE_UPDATE); 68 | } 69 | } 70 | 71 | /** 72 | * @param $validator 73 | * @return $this 74 | */ 75 | public function setValidator($validator) 76 | { 77 | $this->validator = $validator; 78 | return $this; 79 | } 80 | 81 | public function present($results) 82 | { 83 | return $this->parserResult($results); 84 | } 85 | 86 | /** 87 | * @param Model $relateModel 88 | * @return $this 89 | */ 90 | public function setRelateModel(Model $relateModel) 91 | { 92 | $this->relateModel = $relateModel; 93 | if ($relateModel) { 94 | $this->makeModel(); 95 | } 96 | return $this; 97 | } 98 | 99 | /** 100 | * @return Relation 101 | */ 102 | public function relation() 103 | { 104 | return null; 105 | } 106 | 107 | /** 108 | * @return Model 109 | * @throws RepositoryException 110 | */ 111 | public function makeModel() 112 | { 113 | $model = $this->relateModel ? $this->relation() : $this->app->make($this->model()); 114 | 115 | if (!($model instanceof Model || $model instanceof Relation)) { 116 | throw new RepositoryException("Class " . get_class($model) . " must be an instance of Illuminate\\Database\\Eloquent\\Model"); 117 | } 118 | 119 | return $this->model = $model; 120 | } 121 | 122 | 123 | /** 124 | * Retrieve data array for populate field select 125 | * 126 | * @param string $column 127 | * @param string|null $key 128 | * 129 | * @return \Illuminate\Support\Collection|array 130 | */ 131 | public function lists($column, $key = null) 132 | { 133 | $this->applyCriteria(); 134 | $this->applyScope(); 135 | 136 | $lists = $this->model->lists($column, $key); 137 | 138 | $this->resetModel(); 139 | 140 | return $lists; 141 | } 142 | 143 | /** 144 | * Retrieve all data of repository 145 | * 146 | * @param array $columns 147 | * @return mixed 148 | */ 149 | public function all($columns = array('*')) 150 | { 151 | $this->applyCriteria(); 152 | $this->applyScope(); 153 | 154 | if ($this->model instanceof \Illuminate\Database\Eloquent\Builder 155 | || $this->model instanceof \Illuminate\Database\Eloquent\Relations\Relation 156 | ) { 157 | $results = $this->model->get($columns); 158 | } else { 159 | $results = $this->model->all($columns); 160 | } 161 | 162 | $this->resetModel(); 163 | 164 | return $this->parserResult($results); 165 | } 166 | 167 | 168 | /** 169 | * Add a basic where clause to the model. 170 | * 171 | * @param string|array|\Closure $column 172 | * @param mixed $value 173 | * @return $this 174 | */ 175 | protected function modelWhere($column, $value = null) 176 | { 177 | $this->model = $this->model->where($column, $value); 178 | return $this; 179 | } 180 | 181 | /** 182 | * @return \Prettus\Repository\Contracts\PresenterInterface 183 | */ 184 | public function getPresenter() 185 | { 186 | return $this->presenter; 187 | } 188 | 189 | /** 190 | * @param array $meta 191 | */ 192 | public function setPresenterMeta(array $meta) 193 | { 194 | if ($this->presenter instanceof Presenter) { 195 | $this->presenter->setMeta($meta); 196 | } 197 | } 198 | 199 | /** 200 | * @return bool 201 | */ 202 | public function getIsSearchableForceAndWhere() 203 | { 204 | return $this->isSearchableForceAndWhere; 205 | } 206 | 207 | /** 208 | * Find data by where conditions 209 | * 210 | * @param array $where 211 | * 212 | * @return $this 213 | */ 214 | public function where(array $where) 215 | { 216 | $this->applyCriteria(); 217 | $this->applyScope(); 218 | 219 | $this->applyConditions($where); 220 | 221 | return $this; 222 | } 223 | 224 | /** 225 | * Retrieve first data of repository with fail if not found 226 | * 227 | * @param array $columns 228 | * 229 | * @return mixed 230 | */ 231 | public function firstOrFail($columns = ['*']) 232 | { 233 | $this->applyCriteria(); 234 | $this->applyScope(); 235 | 236 | $results = $this->model->firstOrFail($columns); 237 | 238 | $this->resetModel(); 239 | 240 | return $this->parserResult($results); 241 | } 242 | 243 | /** 244 | * Where first 245 | * 246 | * @param array $where 247 | * @param array $columns 248 | * @return mixed 249 | */ 250 | public function whereFirst(array $where, $columns = ['*']) 251 | { 252 | return $this->where($where)->firstOrFail($columns = ['*']); 253 | } 254 | 255 | /** 256 | * Use Model for custom usages 257 | * 258 | * @param callable $callback 259 | * @return $this 260 | */ 261 | public function useModel(callable $callback) 262 | { 263 | $this->model = $callback($this->model); 264 | return $this; 265 | } 266 | 267 | /** 268 | * Remove all or passed registered global scopes. 269 | * 270 | * @param array|null $scopes 271 | * @return $this 272 | */ 273 | public function withoutGlobalScopes(array $scopes = null) 274 | { 275 | $this->model = $this->model->withoutGlobalScopes($scopes); 276 | return $this; 277 | } 278 | 279 | /** 280 | * Pre Apply Criteria for usage 281 | */ 282 | public function preApplyCriteria() 283 | { 284 | $this->applyCriteria(); 285 | $this->skipCriteria(true); 286 | } 287 | 288 | } -------------------------------------------------------------------------------- /src/Someline/Base/Repositories/Interfaces/RepositoryInterface.php: -------------------------------------------------------------------------------- 1 | user(false); 13 | $user = !empty($user) ? $user : \Auth::user(); 14 | if (!$user || !($user instanceof \Someline\Model\Foundation\User)) { 15 | if ($throwException) { 16 | throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException(); 17 | } 18 | } 19 | return $user; 20 | } 21 | 22 | } 23 | 24 | if (!function_exists('auth_check')) { 25 | 26 | /** 27 | * @return boolean 28 | */ 29 | function auth_check() 30 | { 31 | return \Auth::check(); 32 | } 33 | 34 | } 35 | 36 | if (!function_exists('current_full_url')) { 37 | 38 | function current_full_url($withQueryString = true) 39 | { 40 | $url = \Request::url(); 41 | $query = $withQueryString ? (isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : null) : null; 42 | 43 | if ($query) { 44 | $path = \Request::path(); 45 | if (starts_with($query, $path . '&')) { 46 | $query = substr($query, strlen($path) + 1); 47 | } else if (starts_with($query, $path)) { 48 | $query = substr($query, strlen($path)); 49 | } 50 | } 51 | 52 | $url = $query ? $url . '?' . $query : $url; 53 | return $url; 54 | } 55 | 56 | } 57 | 58 | if (!function_exists('smart_get_client_ip')) { 59 | 60 | /** 61 | * @return array|string 62 | */ 63 | function smart_get_client_ip() 64 | { 65 | $request = request(); 66 | $clientIp = $request->header('X-Client-Ip'); 67 | if (empty($clientIp)) { 68 | $clientIp = $request->getClientIp(true); 69 | } 70 | return $clientIp; 71 | } 72 | 73 | } 74 | 75 | if (!function_exists('app_locale')) { 76 | 77 | function app_locale() 78 | { 79 | return \App::getLocale(); 80 | } 81 | 82 | } 83 | 84 | if (!function_exists('app_timezone')) { 85 | 86 | /** 87 | * @return mixed 88 | */ 89 | function app_timezone() 90 | { 91 | return \Config::get("app.timezone"); 92 | } 93 | 94 | } 95 | 96 | if (!function_exists('jwt_token')) { 97 | 98 | /** 99 | * @return string|null 100 | */ 101 | function jwt_token() 102 | { 103 | $jwt_token = \Session::get('jwt_token'); 104 | if (is_jwt_token_valid_for_refresh($jwt_token, true) 105 | || (empty($jwt_token) && \Auth::check()) 106 | ) { 107 | $refreshed_token = refresh_jwt_token(); 108 | if (!empty($refreshed_token)) { 109 | $jwt_token = $refreshed_token; 110 | } 111 | } 112 | return $jwt_token; 113 | } 114 | 115 | } 116 | 117 | if (!function_exists('refresh_jwt_token')) { 118 | 119 | /** 120 | * @return string|null 121 | */ 122 | function refresh_jwt_token() 123 | { 124 | $jwt_token = null; 125 | if (\Auth::check()) { 126 | $jwt_token = \JWTAuth::fromUser(current_auth_user()); 127 | \Session::put('jwt_token', $jwt_token); 128 | } 129 | return $jwt_token; 130 | } 131 | 132 | } 133 | 134 | if (!function_exists('is_jwt_token_valid_for_refresh')) { 135 | 136 | /** 137 | * @param $token 138 | * @param bool $allowExpireRefresh 139 | * @return bool 140 | */ 141 | function is_jwt_token_valid_for_refresh($token, $allowExpireRefresh = false) 142 | { 143 | $is_jwt_token_valid_for_refresh = false; 144 | try { 145 | $payload = \JWTAuth::getPayload($token); 146 | $exp = $payload->get('exp'); 147 | $nbf = $payload->get('nbf'); 148 | if ($exp > 0 && $nbf > 0) { 149 | $nowTime = \Carbon\Carbon::now('UTC'); 150 | $expireTime = \Carbon\Carbon::createFromTimestampUTC($exp); 151 | $validTime = \Carbon\Carbon::createFromTimestampUTC($nbf); 152 | 153 | // if now time is after valid time 154 | if ($nowTime->gt($validTime)) { 155 | $minutesAfterValid = $nowTime->diffInMinutes($validTime); 156 | $minutesBeforeExpire = $nowTime->diffInMinutes($expireTime); 157 | $totalValidLength = $validTime->diffInMinutes($expireTime); 158 | $halfAmountOfMinutes = floor($totalValidLength / 2); 159 | if ($minutesAfterValid >= $halfAmountOfMinutes) { 160 | $is_jwt_token_valid_for_refresh = true; 161 | } 162 | } 163 | } 164 | } catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) { 165 | if ($allowExpireRefresh) { 166 | $is_jwt_token_valid_for_refresh = true; 167 | } 168 | } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) { 169 | } 170 | return $is_jwt_token_valid_for_refresh; 171 | } 172 | 173 | } 174 | 175 | if (!function_exists('phone_parse')) { 176 | 177 | /** 178 | * @param string $phone_number 179 | * @param string $country_code An ISO 3166-1 two letter country code 180 | * @return null|\libphonenumber\PhoneNumber 181 | */ 182 | function phone_parse($phone_number, $country_code) 183 | { 184 | $phoneUtil = \libphonenumber\PhoneNumberUtil::getInstance(); 185 | try { 186 | $phoneNumberProto = $phoneUtil->parseAndKeepRawInput($phone_number, $country_code); 187 | return $phoneNumberProto; 188 | } catch (\libphonenumber\NumberParseException $e) { 189 | return null; 190 | } 191 | } 192 | 193 | } 194 | 195 | if (!function_exists('phone_model_from')) { 196 | 197 | /** 198 | * @param string $phone_number 199 | * @param string $country_code An ISO 3166-1 two letter country code 200 | * @return \Someline\Model\Basic\PhoneNumberModel 201 | */ 202 | function phone_model_from($phone_number, $country_code) 203 | { 204 | return new \Someline\Model\Basic\PhoneNumberModel($phone_number, $country_code); 205 | } 206 | 207 | } 208 | 209 | if (!function_exists('ip_to_country_iso_code')) { 210 | 211 | function ip_to_country_iso_code($ip = null, $default_iso_code = 'US') 212 | { 213 | if (empty($ip)) { 214 | $ip = smart_get_client_ip(); 215 | } 216 | 217 | $location = \GeoIP::getLocation($ip); 218 | 219 | // check if NOT returned default 220 | if ($location['default'] === false && !empty($location['iso_code'])) { 221 | return $location['iso_code']; 222 | } else if ($location['default'] === false && !empty($location['isoCode'])) { 223 | return $location['isoCode']; 224 | } else { 225 | return $default_iso_code; 226 | } 227 | } 228 | 229 | } 230 | 231 | if (!function_exists('collection_paginate')) { 232 | 233 | /** 234 | * @param \Illuminate\Support\Collection $collection 235 | * @param $perPage 236 | * @param string $pageName 237 | * @param null $page 238 | * @return \Illuminate\Pagination\LengthAwarePaginator 239 | */ 240 | function collection_paginate(\Illuminate\Support\Collection $collection, $perPage, $pageName = 'page', $page = null) 241 | { 242 | $page = $page ?: \Illuminate\Pagination\Paginator::resolveCurrentPage($pageName); 243 | 244 | $results = $collection->forPage($page, $perPage); 245 | 246 | parse_str(request()->getQueryString(), $query); 247 | unset($query[$pageName]); 248 | 249 | return new \Illuminate\Pagination\LengthAwarePaginator($results, $collection->count(), $perPage, $page, [ 250 | 'pageName' => $pageName, 251 | 'path' => \Illuminate\Pagination\LengthAwarePaginator::resolveCurrentPath(), 252 | 'query' => $query, 253 | ] 254 | ); 255 | } 256 | 257 | } 258 | 259 | if (!function_exists('str_contains_ascii_only')) { 260 | 261 | function str_contains_ascii_only($string) 262 | { 263 | return (preg_match('%^[ -~]+$%', $string, $m)); 264 | } 265 | 266 | } 267 | 268 | if (!function_exists('in_arrayi')) { 269 | 270 | function in_arrayi($needle, $haystack) 271 | { 272 | return in_array(strtolower($needle), array_map('strtolower', $haystack)); 273 | } 274 | 275 | } 276 | 277 | if (!function_exists('str_random_except')) { 278 | 279 | /** 280 | * Generate a more truly "random" alpha-numeric string. 281 | * 282 | * @param int $length 283 | * @param array $excludes 284 | * @return string 285 | */ 286 | function str_random_except($length = 16, $excludes = []) 287 | { 288 | $string = ''; 289 | $excludes = array_merge(['/', '+', '='], $excludes); 290 | 291 | while (($len = strlen($string)) < $length) { 292 | $size = $length - $len; 293 | 294 | $bytes = random_bytes($size); 295 | 296 | $string .= substr(str_ireplace($excludes, '', base64_encode($bytes)), 0, $size); 297 | } 298 | 299 | return $string; 300 | } 301 | 302 | } -------------------------------------------------------------------------------- /src/Someline/Model/Basic/CountryModel.php: -------------------------------------------------------------------------------- 1 | '+376', 28 | 'AE' => '+971', 29 | 'AF' => '+93', 30 | 'AG' => '+1268', 31 | 'AI' => '+1264', 32 | 'AL' => '+355', 33 | 'AM' => '+374', 34 | 'AO' => '+244', 35 | 'AR' => '+54', 36 | 'AT' => '+43', 37 | 'AU' => '+61', 38 | 'AW' => '+297', 39 | 'AZ' => '+994', 40 | 'BA' => '+387', 41 | 'BB' => '+1246', 42 | 'BD' => '+880', 43 | 'BE' => '+32', 44 | 'BF' => '+226', 45 | 'BG' => '+359', 46 | 'BH' => '+973', 47 | 'BI' => '+257', 48 | 'BJ' => '+229', 49 | 'BM' => '+1441', 50 | 'BN' => '+673', 51 | 'BO' => '+591', 52 | 'BQ' => '+599', 53 | 'BR' => '+55', 54 | 'BS' => '+1242', 55 | 'BT' => '+975', 56 | 'BW' => '+267', 57 | 'BY' => '+375', 58 | 'BZ' => '+501', 59 | 'CA' => '+1', 60 | 'CD' => '+243', 61 | 'CF' => '+236', 62 | 'CG' => '+242', 63 | 'CH' => '+41', 64 | 'CI' => '+225', 65 | 'CK' => '+682', 66 | 'CL' => '+56', 67 | 'CM' => '+237', 68 | 'CN' => '+86', 69 | 'CO' => '+57', 70 | 'CR' => '+506', 71 | 'CU' => '+53', 72 | 'CV' => '+238', 73 | 'CW' => '+599', 74 | 'CY' => '+357', 75 | 'CZ' => '+420', 76 | 'DE' => '+49', 77 | 'DJ' => '+253', 78 | 'DK' => '+45', 79 | 'DM' => '+1767', 80 | 'DO' => '+1809', 81 | 'DZ' => '+213', 82 | 'EC' => '+593', 83 | 'EE' => '+372', 84 | 'EG' => '+20', 85 | 'ES' => '+34', 86 | 'ET' => '+251', 87 | 'FI' => '+358', 88 | 'FJ' => '+679', 89 | 'FO' => '+298', 90 | 'FR' => '+33', 91 | 'GA' => '+241', 92 | 'GB' => '+44', 93 | 'GD' => '+1473', 94 | 'GE' => '+995', 95 | 'GF' => '+594', 96 | 'GH' => '+233', 97 | 'GI' => '+350', 98 | 'GL' => '+299', 99 | 'GM' => '+220', 100 | 'GN' => '+224', 101 | 'GP' => '+590', 102 | 'GQ' => '+240', 103 | 'GR' => '+30', 104 | 'GT' => '+502', 105 | 'GU' => '+1671', 106 | 'GW' => '+245', 107 | 'GY' => '+592', 108 | 'HK' => '+852', 109 | 'HN' => '+504', 110 | 'HR' => '+385', 111 | 'HT' => '+509', 112 | 'HU' => '+36', 113 | 'ID' => '+62', 114 | 'IE' => '+353', 115 | 'IL' => '+972', 116 | 'IN' => '+91', 117 | 'IQ' => '+964', 118 | 'IR' => '+98', 119 | 'IS' => '+354', 120 | 'IT' => '+39', 121 | 'JM' => '+1876', 122 | 'JO' => '+962', 123 | 'JP' => '+81', 124 | 'KE' => '+254', 125 | 'KG' => '+996', 126 | 'KH' => '+855', 127 | 'KI' => '+686', 128 | 'KM' => '+269', 129 | 'KN' => '+1869', 130 | 'KR' => '+82', 131 | 'KW' => '+965', 132 | 'KY' => '+1345', 133 | 'KZ' => '+7', 134 | 'LA' => '+856', 135 | 'LB' => '+961', 136 | 'LC' => '+1758', 137 | 'LI' => '+423', 138 | 'LK' => '+94', 139 | 'LR' => '+231', 140 | 'LS' => '+266', 141 | 'LT' => '+370', 142 | 'LU' => '+352', 143 | 'LV' => '+371', 144 | 'LY' => '+218', 145 | 'MA' => '+212', 146 | 'MC' => '+377', 147 | 'MD' => '+373', 148 | 'ME' => '+382', 149 | 'MG' => '+261', 150 | 'MK' => '+389', 151 | 'ML' => '+223', 152 | 'MM' => '+95', 153 | 'MN' => '+976', 154 | 'MO' => '+853', 155 | 'MQ' => '+596', 156 | 'MR' => '+222', 157 | 'MS' => '+1664', 158 | 'MT' => '+356', 159 | 'MU' => '+230', 160 | 'MV' => '+960', 161 | 'MW' => '+265', 162 | 'MX' => '+52', 163 | 'MY' => '+60', 164 | 'MZ' => '+258', 165 | 'NA' => '+264', 166 | 'NC' => '+687', 167 | 'NE' => '+227', 168 | 'NG' => '+234', 169 | 'NI' => '+505', 170 | 'NL' => '+31', 171 | 'NO' => '+47', 172 | 'NP' => '+977', 173 | 'NZ' => '+64', 174 | 'OM' => '+968', 175 | 'PA' => '+507', 176 | 'PE' => '+51', 177 | 'PF' => '+689', 178 | 'PG' => '+675', 179 | 'PH' => '+63', 180 | 'PK' => '+92', 181 | 'PL' => '+48', 182 | 'PM' => '+508', 183 | 'PR' => '+1787', 184 | 'PS' => '+970', 185 | 'PT' => '+351', 186 | 'PW' => '+680', 187 | 'PY' => '+595', 188 | 'QA' => '+974', 189 | 'RE' => '+262', 190 | 'RO' => '+40', 191 | 'RS' => '+381', 192 | 'RU' => '+7', 193 | 'RW' => '+250', 194 | 'SA' => '+966', 195 | 'SB' => '+677', 196 | 'SC' => '+248', 197 | 'SD' => '+249', 198 | 'SE' => '+46', 199 | 'SG' => '+65', 200 | 'SI' => '+386', 201 | 'SK' => '+421', 202 | 'SL' => '+232', 203 | 'SM' => '+378', 204 | 'SN' => '+221', 205 | 'SO' => '+252', 206 | 'SR' => '+597', 207 | 'SS' => '+211', 208 | 'ST' => '+239', 209 | 'SV' => '+503', 210 | 'SX' => '+1721', 211 | 'SY' => '+963', 212 | 'SZ' => '+268', 213 | 'TC' => '+1649', 214 | 'TD' => '+235', 215 | 'TG' => '+228', 216 | 'TH' => '+66', 217 | 'TJ' => '+992', 218 | 'TL' => '+670', 219 | 'TM' => '+993', 220 | 'TN' => '+216', 221 | 'TO' => '+676', 222 | 'TR' => '+90', 223 | 'TT' => '+1868', 224 | 'TW' => '+886', 225 | 'TZ' => '+255', 226 | 'UA' => '+380', 227 | 'UG' => '+256', 228 | 'US' => '+1', 229 | 'UY' => '+598', 230 | 'UZ' => '+998', 231 | 'VC' => '+1784', 232 | 'VE' => '+58', 233 | 'VG' => '+1284', 234 | 'VI' => '+1340', 235 | 'VN' => '+84', 236 | 'VU' => '+678', 237 | 'WS' => '+685', 238 | 'YE' => '+967', 239 | 'YT' => '+269', 240 | 'ZA' => '+27', 241 | 'ZM' => '+260', 242 | 'ZW' => '+263', 243 | ]; 244 | 245 | public static $country_calling_codes = array( 246 | 'AF' => '+93', 247 | 'AX' => '+358', 248 | 'AL' => '+355', 249 | 'DZ' => '+213', 250 | 'AS' => '+1', 251 | 'AD' => '+376', 252 | 'AO' => '+244', 253 | 'AI' => '+1', 254 | 'AQ' => '+672', 255 | 'AG' => '+1', 256 | 'AR' => '+54', 257 | 'AM' => '+374', 258 | 'AW' => '+297', 259 | 'SH' => '+247', 260 | 'AU' => '+61', 261 | 'AT' => '+43', 262 | 'AZ' => '+994', 263 | 'BS' => '+1', 264 | 'BH' => '+973', 265 | 'BD' => '+880', 266 | 'BB' => '+1', 267 | 'BY' => '+375', 268 | 'BE' => '+32', 269 | 'BZ' => '+501', 270 | 'BJ' => '+229', 271 | 'BM' => '+1', 272 | 'BT' => '+975', 273 | 'BO' => '+591', 274 | 'BQ' => '+599', 275 | 'BA' => '+387', 276 | 'BW' => '+267', 277 | 'BV' => '+47', 278 | 'BR' => '+55', 279 | 'IO' => '+246', 280 | 'BN' => '+673', 281 | 'BG' => '+359', 282 | 'BF' => '+226', 283 | 'BI' => '+257', 284 | 'KH' => '+855', 285 | 'CM' => '+237', 286 | 'CA' => '+1', 287 | 'CV' => '+238', 288 | 'KY' => '+1', 289 | 'CF' => '+236', 290 | 'TD' => '+235', 291 | 'CL' => '+56', 292 | 'CN' => '+86', 293 | 'CX' => '+61', 294 | 'CC' => '+891', 295 | 'CO' => '+57', 296 | 'KM' => '+269', 297 | 'CD' => '+243', 298 | 'CG' => '+242', 299 | 'CK' => '+682', 300 | 'CR' => '+506', 301 | 'CI' => '+225', 302 | 'HR' => '+385', 303 | 'CU' => '+53', 304 | 'CW' => '+599', 305 | 'CY' => '+357', 306 | 'CZ' => '+420', 307 | 'DK' => '+45', 308 | 'DJ' => '+253', 309 | 'DM' => '+1', 310 | 'DO' => '+1', 311 | 'TL' => '+670', 312 | 'EC' => '+593', 313 | 'EG' => '+20', 314 | 'SV' => '+503', 315 | 'GQ' => '+240', 316 | 'ER' => '+291', 317 | 'EE' => '+372', 318 | 'ET' => '+251', 319 | 'FK' => '+500', 320 | 'FO' => '+298', 321 | 'FJ' => '+679', 322 | 'FI' => '+358', 323 | 'FR' => '+33', 324 | 'GF' => '+594', 325 | 'PF' => '+689', 326 | 'TF' => '+262', 327 | 'GA' => '+241', 328 | 'GM' => '+220', 329 | 'GE' => '+995', 330 | 'DE' => '+49', 331 | 'GH' => '+233', 332 | 'GI' => '+350', 333 | 'GR' => '+30', 334 | 'GL' => '+299', 335 | 'GD' => '+1', 336 | 'GP' => '+590', 337 | 'GU' => '+1', 338 | 'GT' => '+502', 339 | 'GG' => '+44', 340 | 'GN' => '+224', 341 | 'GW' => '+245', 342 | 'GY' => '+592', 343 | 'HT' => '+509', 344 | 'HM' => '+61', 345 | 'VA' => '+379', 346 | 'HN' => '+504', 347 | 'HK' => '+852', 348 | 'HU' => '+36', 349 | 'IS' => '+354', 350 | 'IN' => '+91', 351 | 'ID' => '+62', 352 | 'IQ' => '+964', 353 | 'IR' => '+98', 354 | 'IE' => '+353', 355 | 'IM' => '+44', 356 | 'IL' => '+972', 357 | 'IT' => '+39', 358 | 'JM' => '+1', 359 | 'JP' => '+81', 360 | 'JE' => '+44', 361 | 'JO' => '+962', 362 | 'KZ' => '+7', 363 | 'KE' => '+254', 364 | 'KI' => '+686', 365 | 'KP' => '+850', 366 | 'KR' => '+82', 367 | 'XK' => '+377', 368 | 'XK_2' => '381', 369 | 'XK_3' => '386', 370 | 'KW' => '+965', 371 | 'KG' => '+996', 372 | 'LA' => '+856', 373 | 'LV' => '+371', 374 | 'LB' => '+961', 375 | 'LS' => '+266', 376 | 'LR' => '+231', 377 | 'LY' => '+218', 378 | 'LI' => '+423', 379 | 'LT' => '+370', 380 | 'LU' => '+352', 381 | 'MO' => '+853', 382 | 'MK' => '+389', 383 | 'MG' => '+261', 384 | 'MW' => '+265', 385 | 'MY' => '+60', 386 | 'MV' => '+960', 387 | 'ML' => '+223', 388 | 'MT' => '+356', 389 | 'MH' => '+692', 390 | 'MQ' => '+596', 391 | 'MR' => '+222', 392 | 'MU' => '+230', 393 | 'YT' => '+262', 394 | 'MX' => '+52', 395 | 'FM' => '+691', 396 | 'MD' => '+373', 397 | 'MC' => '+377', 398 | 'MN' => '+976', 399 | 'ME' => '+382', 400 | 'MS' => '+1', 401 | 'MA' => '+212', 402 | 'MZ' => '+258', 403 | 'MM' => '+95', 404 | 'NA' => '+264', 405 | 'NR' => '+674', 406 | 'NL' => '+31', 407 | 'BQ' => '+599', 408 | 'NP' => '+977', 409 | 'NC' => '+687', 410 | 'NZ' => '+64', 411 | 'NI' => '+505', 412 | 'NE' => '+227', 413 | 'NG' => '+234', 414 | 'NU' => '+683', 415 | 'NF' => '+672', 416 | 'GB' => '+44', 417 | 'GB_2' => '+28', 418 | 'MP' => '+1', 419 | 'NO' => '+47', 420 | 'OM' => '+968', 421 | 'PK' => '+92', 422 | 'PW' => '+680', 423 | 'PS' => '+970', 424 | 'PA' => '+507', 425 | 'PG' => '+675', 426 | 'PY' => '+595', 427 | 'PE' => '+51', 428 | 'PH' => '+63', 429 | 'PN' => '+64', 430 | 'PL' => '+48', 431 | 'PT' => '+351', 432 | 'PR' => '+1', 433 | 'QA' => '+974', 434 | 'RE' => '+262', 435 | 'RO' => '+40', 436 | 'RU' => '+7', 437 | 'RW' => '+250', 438 | 'BL' => '+590', 439 | 'SH' => '+290', 440 | 'KN' => '+1', 441 | 'LC' => '+1', 442 | 'MF' => '+590', 443 | 'PM' => '+508', 444 | 'VC' => '+1', 445 | 'WS' => '+685', 446 | 'SM' => '+378', 447 | 'ST' => '+239', 448 | 'SA' => '+966', 449 | 'SN' => '+221', 450 | 'RS' => '+381', 451 | 'SC' => '+248', 452 | 'SL' => '+232', 453 | 'SX' => '+1', 454 | 'SG' => '+65', 455 | 'SK' => '+421', 456 | 'SI' => '+386', 457 | 'SB' => '+677', 458 | 'SO' => '+252', 459 | 'ZA' => '+27', 460 | 'GS' => '+500', 461 | 'SS' => '+211', 462 | 'ES' => '+34', 463 | 'LK' => '+94', 464 | 'SD' => '+249', 465 | 'SR' => '+597', 466 | 'SJ' => '+47', 467 | 'SZ' => '+268', 468 | 'SE' => '+46', 469 | 'CH' => '+41', 470 | 'SY' => '+963', 471 | 'TW' => '+886', 472 | 'TJ' => '+992', 473 | 'TZ' => '+255', 474 | 'TH' => '+66', 475 | 'TL' => '+670', 476 | 'TG' => '+228', 477 | 'TK' => '+690', 478 | 'TO' => '+676', 479 | 'TT' => '+1', 480 | 'TN' => '+216', 481 | 'TR' => '+90', 482 | 'TM' => '+993', 483 | 'TC' => '+1', 484 | 'TV' => '+688', 485 | 'UG' => '+256', 486 | 'UA' => '+380', 487 | 'AE' => '+971', 488 | 'GB' => '+44', 489 | 'US' => '+1', 490 | 'UM' => '+1', 491 | 'UY' => '+598', 492 | 'UZ' => '+998', 493 | 'VU' => '+678', 494 | 'VE' => '+58', 495 | 'VN' => '+84', 496 | 'VG' => '+1', 497 | 'VI' => '+1', 498 | 'WF' => '+681', 499 | 'EH' => '+212', 500 | 'YE' => '+967', 501 | 'ZM' => '+260', 502 | 'ZW' => '+263' 503 | ); 504 | 505 | public static function countriesToString(array $countries) 506 | { 507 | if (empty($countries)) { 508 | return ""; 509 | } 510 | 511 | return implode(',', $countries); 512 | } 513 | 514 | public static function countriesFromString($countries_string) 515 | { 516 | if (empty($countries_string)) { 517 | return []; 518 | } 519 | 520 | return explode(',', $countries_string); 521 | } 522 | 523 | public static function getCountryList(array $countries = null, $locale = 'en') 524 | { 525 | $country_list = Countries::getList($locale, 'php', 'cldr'); 526 | 527 | if (empty($countries)) { 528 | return $country_list; 529 | } else { 530 | return array_intersect_key($country_list, array_flip($countries)); 531 | } 532 | } 533 | 534 | public static function getCountryISOCodeList() 535 | { 536 | $country_list = self::getCountryList(); 537 | $country_iso_list = array_keys($country_list); 538 | return $country_iso_list; 539 | } 540 | 541 | public static function getLocalizedCountryList(array $countries = null) 542 | { 543 | $locale = 'en'; 544 | $app_locale = app_locale(); 545 | if ($app_locale == 'cn') { 546 | $locale = 'zh'; 547 | } 548 | return self::getCountryList($countries, $locale); 549 | } 550 | 551 | public static function getCountryCallingCodeList(array $countries = null) 552 | { 553 | // $country_calling_code_list = self::$country_calling_codes; 554 | $country_calling_code_list = self::$nexmo_supported_country_calling_codes; 555 | 556 | if (empty($countries)) { 557 | return $country_calling_code_list; 558 | } else { 559 | return array_intersect_key($country_calling_code_list, array_flip($countries)); 560 | } 561 | } 562 | 563 | public static function getCountryInfo($country_code = null) 564 | { 565 | if (empty($country_code)) { 566 | $country_code = self::getCurrentUserCountry(); 567 | } 568 | 569 | $countryInfoList = self::getCountryInfoIndexedList(); 570 | if (isset($countryInfoList[$country_code])) { 571 | return $countryInfoList[$country_code]; 572 | } else { 573 | return null; 574 | } 575 | } 576 | 577 | public static function getCountryInfoList() 578 | { 579 | $countryCallingCodeList = self::getCountryCallingCodeList(); 580 | $country_iso_codes = array_keys($countryCallingCodeList); 581 | $country_list_en = self::getCountryList($country_iso_codes); 582 | $country_list_locale = self::getLocalizedCountryList($country_iso_codes); 583 | $country_info_list = []; 584 | foreach ($country_iso_codes as $country_iso_code) { 585 | $country_info = []; 586 | if (empty($country_list_en[$country_iso_code]) 587 | || empty($country_list_locale[$country_iso_code]) 588 | ) { 589 | continue; 590 | } else { 591 | $country_info['country_code'] = $country_iso_code; 592 | $country_info['name'] = $country_list_en[$country_iso_code]; 593 | $country_info['locale_name'] = $country_list_locale[$country_iso_code]; 594 | $country_info['combined_name'] = $country_info['country_code'] . ' ' . $country_info['name']; 595 | $country_info['calling_code'] = $countryCallingCodeList[$country_iso_code]; 596 | $country_info_list[] = $country_info; 597 | } 598 | } 599 | return $country_info_list; 600 | } 601 | 602 | public static function getCountryInfoIndexedList() 603 | { 604 | $countryCallingCodeList = self::getCountryCallingCodeList(); 605 | $country_iso_codes = array_keys($countryCallingCodeList); 606 | $country_list_en = self::getCountryList($country_iso_codes); 607 | $country_list_locale = self::getLocalizedCountryList($country_iso_codes); 608 | $country_info_list = []; 609 | foreach ($country_iso_codes as $country_iso_code) { 610 | $country_info = []; 611 | if (empty($country_list_en[$country_iso_code]) 612 | || empty($country_list_locale[$country_iso_code]) 613 | ) { 614 | continue; 615 | } else { 616 | $country_info['country_code'] = $country_iso_code; 617 | $country_info['name'] = $country_list_en[$country_iso_code]; 618 | $country_info['locale_name'] = $country_list_locale[$country_iso_code]; 619 | $country_info['combined_name'] = $country_info['country_code'] . ' ' . $country_info['name']; 620 | $country_info['calling_code'] = $countryCallingCodeList[$country_iso_code]; 621 | $country_info_list[$country_iso_code] = $country_info; 622 | } 623 | } 624 | return $country_info_list; 625 | } 626 | 627 | public static function setCurrentUserCountry($country) 628 | { 629 | if (in_array($country, self::getCountryISOCodeList())) { 630 | \Session::put(self::CURRENT_USER_COUNTRY_KEY, $country); 631 | } else { 632 | \Log::warning("Invalid country [$country]"); 633 | return false; 634 | } 635 | } 636 | 637 | public static function getCurrentUserCountry() 638 | { 639 | return \Session::get(self::CURRENT_USER_COUNTRY_KEY, self::$fallback_country); 640 | } 641 | 642 | } -------------------------------------------------------------------------------- /src/Someline/Model/Basic/PhoneNumberModel.php: -------------------------------------------------------------------------------- 1 | 'FROM_DEFAULT_COUNTRY', 32 | CountryCodeSource::FROM_NUMBER_WITH_IDD => 'FROM_NUMBER_WITH_IDD', 33 | CountryCodeSource::FROM_NUMBER_WITH_PLUS_SIGN => 'FROM_NUMBER_WITH_PLUS_SIGN', 34 | CountryCodeSource::FROM_NUMBER_WITHOUT_PLUS_SIGN => 'FROM_NUMBER_WITHOUT_PLUS_SIGN', 35 | ]; 36 | 37 | private $phoneNumberTypesText = [ 38 | PhoneNumberType::FIXED_LINE => 'FIXED_LINE', 39 | PhoneNumberType::FIXED_LINE_OR_MOBILE => 'FIXED_LINE_OR_MOBILE', 40 | PhoneNumberType::MOBILE => 'MOBILE', 41 | PhoneNumberType::EMERGENCY => 'EMERGENCY', 42 | PhoneNumberType::SHORT_CODE => 'SHORT_CODE', 43 | PhoneNumberType::UNKNOWN => 'UNKNOWN', 44 | ]; 45 | 46 | /** 47 | * Fields from libphonenumber\PhoneNumber 48 | */ 49 | public $country_code; // 65 50 | public $country_code_plus_sign; // +65 51 | public $national_number; 52 | public $extension; 53 | public $country_code_source; // 0 54 | public $country_code_source_text; // FROM_NUMBER_WITH_PLUS_SIGN 55 | public $preferred_domestic_carrier_code; 56 | public $raw_input; 57 | public $raw_input_country; 58 | 59 | /** 60 | * Validation Results 61 | */ 62 | public $is_possible_number = false; 63 | public $is_valid_number = false; 64 | public $is_mobile_number = false; 65 | public $region_code_for_number; // SG 66 | public $number_type; // 1 67 | public $number_type_text; // MOBILE 68 | 69 | /** 70 | * From Formatting 71 | */ 72 | public $format_e164; // +6590919293 73 | public $format_national; // 9091 9293 74 | public $format_international; // +65 9091 9293 75 | public $format_rfc3966; // tel:+65-9091-9293 76 | 77 | /** 78 | * From additional 79 | */ 80 | public $description; // Singapore 81 | public $carrier_name; // M1 82 | public $timezones; // Asia/Singapore 83 | 84 | /** 85 | * PhoneNumberModel constructor. 86 | * @param string $phone_number 87 | * @param string $country_code An ISO 3166-1 two letter country code 88 | */ 89 | public function __construct($phone_number, $country_code) 90 | { 91 | $this->phoneUtil = PhoneNumberUtil::getInstance(); 92 | 93 | $this->phoneNumberProto = phone_parse($phone_number, $country_code); 94 | 95 | $this->raw_input_country = $country_code; 96 | 97 | $this->parse(); 98 | } 99 | 100 | private function parse() 101 | { 102 | if ($this->phoneNumberProto) { 103 | // from phoneNumberProto 104 | $this->country_code = $this->phoneNumberProto->getCountryCode(); 105 | $this->country_code_plus_sign = "+" . $this->country_code; 106 | $this->national_number = $this->phoneNumberProto->getNationalNumber(); 107 | $this->extension = $this->phoneNumberProto->getExtension(); 108 | $this->country_code_source = $this->phoneNumberProto->getCountryCodeSource(); 109 | if (isset($this->countryCodeSourcesText[$this->country_code_source])) { 110 | $this->country_code_source_text = $this->countryCodeSourcesText[$this->country_code_source]; 111 | } 112 | $this->raw_input = $this->phoneNumberProto->getRawInput(); 113 | $this->preferred_domestic_carrier_code = $this->phoneNumberProto->getPreferredDomesticCarrierCode(); 114 | 115 | // from validation 116 | $this->is_possible_number = $this->phoneUtil->isPossibleNumber($this->phoneNumberProto); 117 | $this->is_valid_number = $this->phoneUtil->isValidNumber($this->phoneNumberProto); 118 | $this->region_code_for_number = $this->phoneUtil->getRegionCodeForNumber($this->phoneNumberProto); 119 | $this->number_type = $this->phoneUtil->getNumberType($this->phoneNumberProto); 120 | $this->number_type_text = $this->phoneUtil->getNumberType($this->phoneNumberProto); 121 | if (isset($this->phoneNumberTypesText[$this->number_type])) { 122 | $this->number_type_text = $this->phoneNumberTypesText[$this->number_type]; 123 | } else { 124 | $this->number_type_text = "OTHER"; 125 | } 126 | $this->is_mobile_number = in_array($this->number_type, [ 127 | PhoneNumberType::FIXED_LINE_OR_MOBILE, 128 | PhoneNumberType::MOBILE, 129 | ]); 130 | 131 | // from formatting 132 | $this->format_e164 = $this->phoneUtil->format($this->phoneNumberProto, PhoneNumberFormat::E164); 133 | $this->format_international = $this->phoneUtil->format($this->phoneNumberProto, PhoneNumberFormat::INTERNATIONAL); 134 | $this->format_national = $this->phoneUtil->format($this->phoneNumberProto, PhoneNumberFormat::NATIONAL); 135 | $this->format_rfc3966 = $this->phoneUtil->format($this->phoneNumberProto, PhoneNumberFormat::RFC3966); 136 | 137 | // from additional 138 | $phoneNumberOfflineGeocoder = PhoneNumberOfflineGeocoder::getInstance(); 139 | $this->description = $phoneNumberOfflineGeocoder->getDescriptionForNumber($this->phoneNumberProto, 'en'); 140 | 141 | $phoneNumberToCarrierMapper = PhoneNumberToCarrierMapper::getInstance(); 142 | $this->carrier_name = $phoneNumberToCarrierMapper->getNameForNumber($this->phoneNumberProto, 'en'); 143 | 144 | $phoneNumberToTimeZonesMapper = PhoneNumberToTimeZonesMapper::getInstance(); 145 | $this->timezones = $phoneNumberToTimeZonesMapper->getTimeZonesForNumber($this->phoneNumberProto); 146 | } 147 | } 148 | 149 | public function isValid() 150 | { 151 | return $this->phoneNumberProto != null; 152 | } 153 | 154 | public function isValidNumberForRegion($country_code) 155 | { 156 | return $this->phoneUtil->isValidNumberForRegion($this->phoneNumber, $country_code); 157 | } 158 | 159 | public function isValidNumber() 160 | { 161 | return $this->is_valid_number; 162 | } 163 | 164 | public function isMobileNumber() 165 | { 166 | return $this->is_mobile_number; 167 | } 168 | 169 | public function __toString() 170 | { 171 | return (string)$this->phoneNumberProto; 172 | } 173 | 174 | public function equals(PhoneNumberModel $other) 175 | { 176 | if (empty($this->isValid()) || empty($other->isValid())) { 177 | return false; 178 | } 179 | return $this->phoneNumberProto->equals($other->phoneNumberProto); 180 | } 181 | 182 | public function toArray() 183 | { 184 | return [ 185 | 'country_code' => $this->country_code, 186 | 'country_code_plus_sign' => $this->country_code_plus_sign, 187 | 'national_number' => $this->national_number, 188 | 'extension' => $this->extension, 189 | 'country_code_source' => $this->country_code_source, 190 | 'country_code_source_text' => $this->country_code_source_text, 191 | 'preferred_domestic_carrier_code' => $this->preferred_domestic_carrier_code, 192 | 'raw_input' => $this->raw_input, 193 | 'raw_input_country' => $this->raw_input_country, 194 | 195 | 'is_possible_number' => $this->is_possible_number, 196 | 'is_valid_number' => $this->is_valid_number, 197 | 'is_mobile_number' => $this->is_mobile_number, 198 | 'region_code_for_number' => $this->region_code_for_number, 199 | 'number_type' => $this->number_type, 200 | 'number_type_text' => $this->number_type_text, 201 | 202 | 'format_e164' => $this->format_e164, 203 | 'format_national' => $this->format_national, 204 | 'format_international' => $this->format_international, 205 | 'format_rfc3966' => $this->format_rfc3966, 206 | 207 | 'description' => $this->description, 208 | 'carrier_name' => $this->carrier_name, 209 | 'timezones' => $this->timezones, 210 | ]; 211 | } 212 | 213 | } -------------------------------------------------------------------------------- /src/Someline/Model/Foundation/User.php: -------------------------------------------------------------------------------- 1 | creating > created > saved 21 | * @UPDATE: saving > updating > updated > saved 22 | * 23 | */ 24 | class BaseModelObserver 25 | { 26 | public function creating(BaseModelEventsInterface $model) 27 | { 28 | $model->onCreating(); 29 | } 30 | 31 | public function created(BaseModelEventsInterface $model) 32 | { 33 | $model->onCreated(); 34 | } 35 | 36 | public function updating(BaseModelEventsInterface $model) 37 | { 38 | $model->onUpdating(); 39 | } 40 | 41 | public function updated(BaseModelEventsInterface $model) 42 | { 43 | $model->onUpdated(); 44 | } 45 | 46 | public function saving(BaseModelEventsInterface $model) 47 | { 48 | $model->onSaving(); 49 | } 50 | 51 | public function saved(BaseModelEventsInterface $model) 52 | { 53 | $model->onSaved(); 54 | } 55 | 56 | public function deleting(BaseModelEventsInterface $model) 57 | { 58 | $model->onDeleting(); 59 | } 60 | 61 | public function deleted(BaseModelEventsInterface $model) 62 | { 63 | $model->onDeleted(); 64 | } 65 | 66 | public function restoring(BaseModelEventsInterface $model) 67 | { 68 | $model->onRestoring(); 69 | } 70 | 71 | public function restored(BaseModelEventsInterface $model) 72 | { 73 | $model->onRestored(); 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /src/Someline/Model/Traits/BaseModelEvents.php: -------------------------------------------------------------------------------- 1 | creating > created > saved 21 | * @UPDATE: saving > updating > updated > saved 22 | * 23 | */ 24 | trait BaseModelEvents 25 | { 26 | 27 | protected static function boot() 28 | { 29 | parent::boot(); 30 | 31 | /** @var Model $ModelName */ 32 | $ModelName = get_called_class(); 33 | 34 | // Setup event bindings... 35 | $ModelName::observe(new BaseModelObserver); 36 | } 37 | 38 | public function onCreating() 39 | { 40 | 41 | // auto set user id 42 | if ($this->autoUserId && empty($this->user_id)) { 43 | $user_id = $this->getAuthUserId(); 44 | if ($this->validUserId($user_id)) { 45 | $this->user_id = $user_id; 46 | } 47 | } 48 | 49 | } 50 | 51 | public function onCreated() 52 | { 53 | } 54 | 55 | public function onUpdating() 56 | { 57 | } 58 | 59 | public function onUpdated() 60 | { 61 | } 62 | 63 | public function onSaving() 64 | { 65 | 66 | // update ips if true 67 | if ($this->ips) { 68 | $this->updateIps(); 69 | } 70 | 71 | // update users if true 72 | if ($this->update_users) { 73 | $this->updateUsers(); 74 | } 75 | 76 | } 77 | 78 | public function onSaved() 79 | { 80 | } 81 | 82 | public function onDeleting() 83 | { 84 | } 85 | 86 | public function onDeleted() 87 | { 88 | } 89 | 90 | public function onRestoring() 91 | { 92 | } 93 | 94 | public function onRestored() 95 | { 96 | } 97 | 98 | /** 99 | * check the $user_id is valid. 100 | * 101 | * @param int|string $user_id 102 | * @return bool 103 | */ 104 | protected function validUserId($user_id): bool 105 | { 106 | if ('int' === $this->keyType) 107 | return $user_id > 0; 108 | 109 | if ('string' === $this->keyType) 110 | return strlen($user_id) > 0; 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /src/Someline/Presenters/BasicPresenter.php: -------------------------------------------------------------------------------- 1 | transformer = $transformer; 26 | } 27 | 28 | /** 29 | * Transformer 30 | * 31 | * @return \League\Fractal\TransformerAbstract 32 | */ 33 | public function getTransformer() 34 | { 35 | if ($this->transformer) { 36 | return new $this->transformer(); 37 | } else { 38 | return new BasicTransformer(); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/Someline/Repositories/Criteria/AuthUserCriteria.php: -------------------------------------------------------------------------------- 1 | where('user_id', '=', current_auth_user()->user_id); 18 | return $model; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/Someline/Repositories/Criteria/OwnerUsersCriteria.php: -------------------------------------------------------------------------------- 1 | userIds = $userIds; 24 | } 25 | 26 | public function apply($model, RepositoryInterface $repository) 27 | { 28 | $model = $model->whereIn('user_id', $this->userIds); 29 | return $model; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/Someline/Repositories/Criteria/RequestCriteria.php: -------------------------------------------------------------------------------- 1 | getFieldsSearchable(); 28 | $search = $this->request->get(config('repository.criteria.params.search', 'search'), null); 29 | $searchFields = $this->request->get(config('repository.criteria.params.searchFields', 'searchFields'), null); 30 | $filter = $this->request->get(config('repository.criteria.params.filter', 'filter'), null); 31 | $orderBy = $this->request->get(config('repository.criteria.params.orderBy', 'orderBy'), null); 32 | $sortedBy = $this->request->get(config('repository.criteria.params.sortedBy', 'sortedBy'), 'asc'); 33 | $with = $this->request->get(config('repository.criteria.params.with', 'with'), null); 34 | $sortedBy = !empty($sortedBy) ? $sortedBy : 'asc'; 35 | 36 | if ($search && is_array($fieldsSearchable) && count($fieldsSearchable)) { 37 | 38 | $searchFields = is_array($searchFields) || is_null($searchFields) ? $searchFields : explode(';', $searchFields); 39 | $fields = $this->parserFieldsSearch($fieldsSearchable, $searchFields); 40 | $isFirstField = true; 41 | $searchData = $this->parserSearchData($search); 42 | $search = $this->parserSearchValue($search); 43 | $modelForceAndWhere = method_exists($repository, 'getIsSearchableForceAndWhere') ? $repository->getIsSearchableForceAndWhere() : false; 44 | 45 | $model = $model->where(function ($query) use ($fields, $search, $searchData, $isFirstField, $modelForceAndWhere) { 46 | /** @var Builder $query */ 47 | 48 | foreach ($fields as $field => $condition) { 49 | 50 | if (is_numeric($field)) { 51 | $field = $condition; 52 | $condition = "="; 53 | } 54 | 55 | $value = null; 56 | 57 | $condition = trim(strtolower($condition)); 58 | 59 | if (isset($searchData[$field])) { 60 | if ($condition == "like_raw") { 61 | $condition = "like"; 62 | $value = $searchData[$field]; 63 | } else if ($condition == "like_safe") { 64 | $condition = "like"; 65 | if (str_contains_ascii_only($searchData[$field])) { 66 | $value = "%{$searchData[$field]}%"; 67 | } else { 68 | $value = null; 69 | } 70 | } else { 71 | $value = ($condition == "like" || $condition == "ilike") ? "%{$searchData[$field]}%" : $searchData[$field]; 72 | } 73 | } else { 74 | if (!is_null($search)) { 75 | if ($condition == "like_raw") { 76 | $condition = "like"; 77 | $value = $searchData[$field]; 78 | } else if ($condition == "like_safe") { 79 | $condition = "like"; 80 | if (str_contains_ascii_only($search)) { 81 | $value = "%{$search}%"; 82 | } else { 83 | $value = null; 84 | } 85 | } else { 86 | $value = ($condition == "like" || $condition == "ilike") ? "%{$search}%" : $search; 87 | } 88 | } 89 | } 90 | 91 | $relation = null; 92 | if (stripos($field, '.')) { 93 | $explode = explode('.', $field); 94 | $field = array_pop($explode); 95 | $relation = implode('.', $explode); 96 | } 97 | $modelTableName = $query->getModel()->getTable(); 98 | if ($isFirstField || $modelForceAndWhere) { 99 | if (!is_null($value)) { 100 | if (!is_null($relation)) { 101 | $query->whereHas($relation, function ($query) use ($field, $condition, $value) { 102 | $query->where($field, $condition, $value); 103 | }); 104 | } else { 105 | $query->where($modelTableName . '.' . $field, $condition, $value); 106 | } 107 | $isFirstField = false; 108 | } 109 | } else { 110 | if (!is_null($value)) { 111 | if (!is_null($relation)) { 112 | $query->orWhereHas($relation, function ($query) use ($field, $condition, $value) { 113 | $query->where($field, $condition, $value); 114 | }); 115 | } else { 116 | $query->orWhere($modelTableName . '.' . $field, $condition, $value); 117 | } 118 | } 119 | } 120 | } 121 | }); 122 | } 123 | 124 | if (isset($orderBy) && !empty($orderBy)) { 125 | $orderBys = explode(';', $orderBy); // products:product_id:product_id|products.name;updated_at,desc 126 | $originSortedBy = $sortedBy; 127 | foreach ($orderBys as $orderBy) { 128 | // split sorted by 129 | $splitSortedBy = explode(',', $orderBy); 130 | if (count($splitSortedBy) > 1) { 131 | $sortedBy = $splitSortedBy[1]; 132 | } else { 133 | $sortedBy = $originSortedBy; 134 | } 135 | $orderBy = $splitSortedBy[0]; 136 | 137 | // split joint 138 | $split = explode('|', $orderBy); 139 | if (count($split) > 1) { 140 | /* 141 | * ex. 142 | * products|description -> join products on current_table.product_id = products.id order by description 143 | * 144 | * products:custom_id|products.description -> join products on current_table.custom_id = products.id order 145 | * by products.description (in case both tables have same column name) 146 | */ 147 | $table = $model->getModel()->getTable(); 148 | $sortTable = $split[0]; 149 | $sortColumn = $split[1]; 150 | 151 | $sortTableKeyName = 'id'; 152 | $split = explode(':', $sortTable); 153 | if (count($split) > 2) { // products:custom_id:products_table_custom_id|products.description 154 | $sortTable = $split[0]; 155 | $keyName = $table . '.' . $split[1]; 156 | $sortTableKeyName = $split[2]; 157 | } else if (count($split) > 1) { 158 | $sortTable = $split[0]; 159 | $keyName = $table . '.' . $split[1]; 160 | } else { 161 | /* 162 | * If you do not define which column to use as a joining column on current table, it will 163 | * use a singular of a join table appended with _id 164 | * 165 | * ex. 166 | * products -> product_id 167 | */ 168 | $prefix = rtrim($sortTable, 's'); 169 | $keyName = $table . '.' . $prefix . '_id'; 170 | } 171 | 172 | $model = $model 173 | ->leftJoin($sortTable, $keyName, '=', $sortTable . '.' . $sortTableKeyName) 174 | ->orderBy($sortColumn, $sortedBy) 175 | ->groupBy($keyName) // Prevent SQL Error: SELECT list is not in GROUP BY clause and contains nonaggregated column 'xxx' which is not functionally dependent on columns in GROUP BY clause; 176 | ->addSelect($table . '.*'); 177 | } else { 178 | $model = $model->orderBy($orderBy, $sortedBy); 179 | } 180 | } 181 | } 182 | 183 | if (isset($filter) && !empty($filter)) { 184 | if (is_string($filter)) { 185 | $filter = explode(';', $filter); 186 | } 187 | 188 | $model = $model->select($filter); 189 | } 190 | 191 | if ($with) { 192 | $with = explode(';', $with); 193 | $model = $model->with($with); 194 | } 195 | 196 | return $model; 197 | } 198 | 199 | protected function parserFieldsSearch(array $fields = [], array $searchFields = null) 200 | { 201 | if (!is_null($searchFields) && count($searchFields)) { 202 | $acceptedConditions = config('repository.criteria.acceptedConditions', [ 203 | '=', 204 | 'like', 205 | 'like_raw', 206 | ]); 207 | $originalFields = $fields; 208 | $fields = []; 209 | 210 | foreach ($searchFields as $index => $field) { 211 | $field_parts = explode(':', $field); 212 | $temporaryIndex = array_search($field_parts[0], $originalFields); 213 | 214 | if (count($field_parts) == 2) { 215 | if (in_array($field_parts[1], $acceptedConditions)) { 216 | unset($originalFields[$temporaryIndex]); 217 | $field = $field_parts[0]; 218 | $condition = $field_parts[1]; 219 | $originalFields[$field] = $condition; 220 | $searchFields[$index] = $field; 221 | } 222 | } 223 | } 224 | 225 | foreach ($originalFields as $field => $condition) { 226 | if (is_numeric($field)) { 227 | $field = $condition; 228 | $condition = "="; 229 | } 230 | if (in_array($field, $searchFields)) { 231 | $fields[$field] = $condition; 232 | } 233 | } 234 | 235 | if (count($fields) == 0) { 236 | throw new \Exception(trans('repository::criteria.fields_not_accepted', ['field' => implode(',', $searchFields)])); 237 | } 238 | 239 | } 240 | 241 | return $fields; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/Someline/Repositories/PresenterRepository.php: -------------------------------------------------------------------------------- 1 | setTransformer($transformer); 28 | $this->presenter = $basicPresenter; 29 | $this->skipPresenter = $skipPresenter; 30 | } 31 | 32 | /** 33 | * @return bool 34 | */ 35 | public function isSkipPresenter(): bool 36 | { 37 | return $this->skipPresenter; 38 | } 39 | 40 | /** 41 | * @param bool $skipPresenter 42 | */ 43 | public function setSkipPresenter(bool $skipPresenter) 44 | { 45 | $this->skipPresenter = $skipPresenter; 46 | } 47 | 48 | /** 49 | * @return null 50 | */ 51 | public function getPresenter() 52 | { 53 | return $this->presenter; 54 | } 55 | 56 | /** 57 | * @param null|PresenterInterface $presenter 58 | */ 59 | public function setPresenter(PresenterInterface $presenter) 60 | { 61 | $this->presenter = $presenter; 62 | } 63 | 64 | /** 65 | * Wrapper result data 66 | * 67 | * @param mixed $result 68 | * 69 | * @return mixed 70 | */ 71 | public function parserResult($result) 72 | { 73 | if ($this->presenter instanceof PresenterInterface) { 74 | 75 | if ($result instanceof Collection || $result instanceof LengthAwarePaginator) { 76 | $result->each(function ($model) { 77 | if ($model instanceof Presentable) { 78 | $model->setPresenter($this->presenter); 79 | } 80 | 81 | return $model; 82 | }); 83 | } elseif ($result instanceof Presentable) { 84 | $result = $result->setPresenter($this->presenter); 85 | } 86 | 87 | if (!$this->skipPresenter) { 88 | return $this->presenter->present($result); 89 | } 90 | } 91 | 92 | return $result; 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/BindingsGenerator.php: -------------------------------------------------------------------------------- 1 | getPath()); 30 | $repositoryInterface = '\\' . $this->getRepository() . "::class"; 31 | $repositoryEloquent = '\\' . $this->getEloquentRepository() . "::class"; 32 | \File::put($this->getPath(), str_replace($this->bindPlaceholder, "\$this->app->bind({$repositoryInterface}, $repositoryEloquent);" . PHP_EOL . ' ' . $this->bindPlaceholder, $provider)); 33 | } 34 | 35 | /** 36 | * Get destination path for generated file. 37 | * 38 | * @return string 39 | */ 40 | public function getPath() 41 | { 42 | return $this->getBasePath() . '/Providers/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '.php'; 43 | } 44 | 45 | /** 46 | * Get base path of destination file. 47 | * 48 | * @return string 49 | */ 50 | public function getBasePath() 51 | { 52 | return config('repository.generator.basePath', app_path()); 53 | } 54 | 55 | /** 56 | * Get generator path config node. 57 | * 58 | * @return string 59 | */ 60 | public function getPathConfigNode() 61 | { 62 | return 'provider'; 63 | } 64 | 65 | /** 66 | * Gets repository full class name 67 | * 68 | * @return string 69 | */ 70 | public function getRepository() 71 | { 72 | $repositoryGenerator = new RepositoryInterfaceGenerator([ 73 | 'name' => $this->name, 74 | ]); 75 | 76 | $repository = $repositoryGenerator->getRootNamespace() . '\\' . $repositoryGenerator->getName(); 77 | 78 | return str_replace([ 79 | "\\", 80 | '/' 81 | ], '\\', $repository) . 'Repository'; 82 | } 83 | 84 | /** 85 | * Gets eloquent repository full class name 86 | * 87 | * @return string 88 | */ 89 | public function getEloquentRepository() 90 | { 91 | $repositoryGenerator = new RepositoryEloquentGenerator([ 92 | 'name' => $this->name, 93 | ]); 94 | 95 | $repository = $repositoryGenerator->getRootNamespace() . '\\' . $repositoryGenerator->getName(); 96 | 97 | return str_replace([ 98 | "\\", 99 | '/' 100 | ], '\\', $repository) . 'RepositoryEloquent'; 101 | } 102 | 103 | /** 104 | * Get root namespace. 105 | * 106 | * @return string 107 | */ 108 | public function getRootNamespace() 109 | { 110 | return parent::getRootNamespace() . parent::getConfigGeneratorClassPath($this->getPathConfigNode()); 111 | } 112 | 113 | /** 114 | * Get array replacements. 115 | * 116 | * @return array 117 | */ 118 | public function getReplacements() 119 | { 120 | 121 | return array_merge(parent::getReplacements(), [ 122 | 'repository' => $this->getRepository(), 123 | 'eloquent' => $this->getEloquentRepository(), 124 | 'placeholder' => $this->bindPlaceholder, 125 | ]); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/BindingsCommand.php: -------------------------------------------------------------------------------- 1 | $this->argument('name'), 47 | 'force' => $this->option('force'), 48 | ]); 49 | // generate repository service provider 50 | if (!file_exists($bindingGenerator->getPath())) { 51 | $this->call('make:provider', [ 52 | 'name' => $bindingGenerator->getConfigGeneratorClassPath($bindingGenerator->getPathConfigNode()), 53 | ]); 54 | // placeholder to mark the place in file where to prepend repository bindings 55 | $provider = File::get($bindingGenerator->getPath()); 56 | File::put($bindingGenerator->getPath(), vsprintf(str_replace('//', '%s', $provider), [ 57 | '//', 58 | $bindingGenerator->bindPlaceholder 59 | ])); 60 | } 61 | $bindingGenerator->run(); 62 | $this->info($this->type . ' created successfully.'); 63 | } catch (FileAlreadyExistsException $e) { 64 | $this->error($this->type . ' already exists!'); 65 | 66 | return false; 67 | } 68 | } 69 | 70 | 71 | /** 72 | * The array of command arguments. 73 | * 74 | * @return array 75 | */ 76 | public function getArguments() 77 | { 78 | return [ 79 | [ 80 | 'name', 81 | InputArgument::REQUIRED, 82 | 'The name of model for which the controller is being generated.', 83 | null 84 | ], 85 | ]; 86 | } 87 | 88 | 89 | /** 90 | * The array of command options. 91 | * 92 | * @return array 93 | */ 94 | public function getOptions() 95 | { 96 | return [ 97 | [ 98 | 'force', 99 | 'f', 100 | InputOption::VALUE_NONE, 101 | 'Force the creation if file already exists.', 102 | null 103 | ], 104 | ]; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/CommandBase.php: -------------------------------------------------------------------------------- 1 | fire(); 14 | } 15 | 16 | public function fire() 17 | { 18 | // ... 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/ControllerCommand.php: -------------------------------------------------------------------------------- 1 | call('make:request', [ 46 | 'name' => $this->argument('name') . 'CreateRequest' 47 | ]); 48 | // Generate update request for controller 49 | $this->call('make:request', [ 50 | 'name' => $this->argument('name') . 'UpdateRequest' 51 | ]); 52 | 53 | (new ControllerGenerator([ 54 | 'name' => $this->argument('name'), 55 | 'force' => $this->option('force'), 56 | ]))->run(); 57 | $this->info($this->type . ' created successfully.'); 58 | } catch (FileAlreadyExistsException $e) { 59 | $this->error($this->type . ' already exists!'); 60 | 61 | return false; 62 | } 63 | } 64 | 65 | 66 | /** 67 | * The array of command arguments. 68 | * 69 | * @return array 70 | */ 71 | public function getArguments() 72 | { 73 | return [ 74 | [ 75 | 'name', 76 | InputArgument::REQUIRED, 77 | 'The name of model for which the controller is being generated.', 78 | null 79 | ], 80 | ]; 81 | } 82 | 83 | 84 | /** 85 | * The array of command options. 86 | * 87 | * @return array 88 | */ 89 | public function getOptions() 90 | { 91 | return [ 92 | [ 93 | 'force', 94 | 'f', 95 | InputOption::VALUE_NONE, 96 | 'Force the creation if file already exists.', 97 | null 98 | ], 99 | ]; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/CriteriaCommand.php: -------------------------------------------------------------------------------- 1 | $this->argument('name'), 43 | 'force' => $this->option('force'), 44 | ]))->run(); 45 | 46 | $this->info("Criteria created successfully."); 47 | } catch (FileAlreadyExistsException $ex) { 48 | $this->error($this->type . ' already exists!'); 49 | return false; 50 | } 51 | } 52 | 53 | /** 54 | * The array of command arguments. 55 | * 56 | * @return array 57 | */ 58 | public function getArguments() 59 | { 60 | return [ 61 | [ 62 | 'name', 63 | InputArgument::REQUIRED, 64 | 'The name of class being generated.', 65 | null 66 | ], 67 | ]; 68 | } 69 | 70 | /** 71 | * The array of command options. 72 | * 73 | * @return array 74 | */ 75 | public function getOptions() 76 | { 77 | return [ 78 | [ 79 | 'force', 80 | 'f', 81 | InputOption::VALUE_NONE, 82 | 'Force the creation if file already exists.', 83 | null 84 | ], 85 | ]; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/EntityCommand.php: -------------------------------------------------------------------------------- 1 | option('presenter'); 41 | if (is_null($presenter) && $this->confirm('Would you like to create a Presenter? [y|N]')) { 42 | $presenter = 'yes'; 43 | } 44 | 45 | if ($presenter == 'yes') { 46 | $this->call('starter:presenter', [ 47 | 'name' => $this->argument('name'), 48 | '--force' => $this->option('force'), 49 | ]); 50 | } 51 | 52 | $validator = $this->option('validator'); 53 | if (is_null($validator) && $this->confirm('Would you like to create a Validator? [y|N]')) { 54 | $validator = 'yes'; 55 | } 56 | 57 | if ($validator == 'yes') { 58 | $this->call('starter:validator', [ 59 | 'name' => $this->argument('name'), 60 | '--rules' => $this->option('rules'), 61 | '--force' => $this->option('force'), 62 | ]); 63 | } 64 | 65 | if ($this->confirm('Would you like to create a Controller? [y|N]')) { 66 | 67 | // Generate a controller resource 68 | $this->call('starter:controller', [ 69 | 'name' => $this->argument('name'), 70 | '--force' => $this->option('force') 71 | ]); 72 | } 73 | 74 | $this->call('starter:repository', [ 75 | 'name' => $this->argument('name'), 76 | '--fillable' => $this->option('fillable'), 77 | '--rules' => $this->option('rules'), 78 | '--validator' => $validator, 79 | '--presenter' => $presenter, 80 | '--force' => $this->option('force') 81 | ]); 82 | 83 | $this->call('starter:bindings', [ 84 | 'name' => $this->argument('name'), 85 | '--force' => $this->option('force') 86 | ]); 87 | } 88 | 89 | 90 | /** 91 | * The array of command arguments. 92 | * 93 | * @return array 94 | */ 95 | public function getArguments() 96 | { 97 | return [ 98 | [ 99 | 'name', 100 | InputArgument::REQUIRED, 101 | 'The name of class being generated.', 102 | null 103 | ], 104 | ]; 105 | } 106 | 107 | 108 | /** 109 | * The array of command options. 110 | * 111 | * @return array 112 | */ 113 | public function getOptions() 114 | { 115 | return [ 116 | [ 117 | 'fillable', 118 | null, 119 | InputOption::VALUE_OPTIONAL, 120 | 'The fillable attributes.', 121 | null 122 | ], 123 | [ 124 | 'rules', 125 | null, 126 | InputOption::VALUE_OPTIONAL, 127 | 'The rules of validation attributes.', 128 | null 129 | ], 130 | [ 131 | 'validator', 132 | null, 133 | InputOption::VALUE_OPTIONAL, 134 | 'Adds validator reference to the repository.', 135 | null 136 | ], 137 | [ 138 | 'presenter', 139 | null, 140 | InputOption::VALUE_OPTIONAL, 141 | 'Adds presenter reference to the repository.', 142 | null 143 | ], 144 | [ 145 | 'force', 146 | 'f', 147 | InputOption::VALUE_NONE, 148 | 'Force the creation if file already exists.', 149 | null 150 | ] 151 | ]; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/PresenterCommand.php: -------------------------------------------------------------------------------- 1 | $this->argument('name'), 47 | 'force' => $this->option('force'), 48 | ]))->run(); 49 | $this->info("Presenter created successfully."); 50 | 51 | if (!\File::exists(app_path() . '/Transformers/' . $this->argument('name') . 'Transformer.php')) { 52 | if ($this->confirm('Would you like to create a Transformer? [y|N]')) { 53 | (new TransformerGenerator([ 54 | 'name' => $this->argument('name'), 55 | 'force' => $this->option('force'), 56 | ]))->run(); 57 | $this->info("Transformer created successfully."); 58 | } 59 | } 60 | } catch (FileAlreadyExistsException $e) { 61 | $this->error($this->type . ' already exists!'); 62 | 63 | return false; 64 | } 65 | } 66 | 67 | 68 | /** 69 | * The array of command arguments. 70 | * 71 | * @return array 72 | */ 73 | public function getArguments() 74 | { 75 | return [ 76 | [ 77 | 'name', 78 | InputArgument::REQUIRED, 79 | 'The name of model for which the presenter is being generated.', 80 | null 81 | ], 82 | ]; 83 | } 84 | 85 | 86 | /** 87 | * The array of command options. 88 | * 89 | * @return array 90 | */ 91 | public function getOptions() 92 | { 93 | return [ 94 | [ 95 | 'force', 96 | 'f', 97 | InputOption::VALUE_NONE, 98 | 'Force the creation if file already exists.', 99 | null 100 | ] 101 | ]; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/RepositoryCommand.php: -------------------------------------------------------------------------------- 1 | generators = new Collection(); 52 | 53 | $this->generators->push(new MigrationGenerator([ 54 | 'name' => 'create_' . snake_case(str_plural($this->argument('name'))) . '_table', 55 | 'fields' => $this->option('fillable'), 56 | 'force' => $this->option('force'), 57 | ])); 58 | 59 | $modelGenerator = new ModelGenerator([ 60 | 'name' => $this->argument('name'), 61 | 'fillable' => $this->option('fillable'), 62 | 'force' => $this->option('force') 63 | ]); 64 | 65 | $this->generators->push($modelGenerator); 66 | 67 | $this->generators->push(new RepositoryInterfaceGenerator([ 68 | 'name' => $this->argument('name'), 69 | 'force' => $this->option('force'), 70 | ])); 71 | 72 | foreach ($this->generators as $generator) { 73 | $generator->run(); 74 | } 75 | 76 | $model = $modelGenerator->getRootNamespace() . '\\' . $modelGenerator->getName(); 77 | $model = str_replace([ 78 | "\\", 79 | '/' 80 | ], '\\', $model); 81 | 82 | try { 83 | (new RepositoryEloquentGenerator([ 84 | 'name' => $this->argument('name'), 85 | 'rules' => $this->option('rules'), 86 | 'validator' => $this->option('validator'), 87 | 'presenter' => $this->option('presenter'), 88 | 'force' => $this->option('force'), 89 | 'model' => $model 90 | ]))->run(); 91 | $this->info("Repository created successfully."); 92 | } catch (FileAlreadyExistsException $e) { 93 | $this->error($this->type . ' already exists!'); 94 | 95 | return false; 96 | } 97 | } 98 | 99 | 100 | /** 101 | * The array of command arguments. 102 | * 103 | * @return array 104 | */ 105 | public function getArguments() 106 | { 107 | return [ 108 | [ 109 | 'name', 110 | InputArgument::REQUIRED, 111 | 'The name of class being generated.', 112 | null 113 | ], 114 | ]; 115 | } 116 | 117 | 118 | /** 119 | * The array of command options. 120 | * 121 | * @return array 122 | */ 123 | public function getOptions() 124 | { 125 | return [ 126 | [ 127 | 'fillable', 128 | null, 129 | InputOption::VALUE_OPTIONAL, 130 | 'The fillable attributes.', 131 | null 132 | ], 133 | [ 134 | 'rules', 135 | null, 136 | InputOption::VALUE_OPTIONAL, 137 | 'The rules of validation attributes.', 138 | null 139 | ], 140 | [ 141 | 'validator', 142 | null, 143 | InputOption::VALUE_OPTIONAL, 144 | 'Adds validator reference to the repository.', 145 | null 146 | ], 147 | [ 148 | 'presenter', 149 | null, 150 | InputOption::VALUE_OPTIONAL, 151 | 'Adds presenter reference to the repository.', 152 | null 153 | ], 154 | [ 155 | 'force', 156 | 'f', 157 | InputOption::VALUE_NONE, 158 | 'Force the creation if file already exists.', 159 | null 160 | ] 161 | ]; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/TransformerCommand.php: -------------------------------------------------------------------------------- 1 | $this->argument('name'), 45 | 'force' => $this->option('force'), 46 | ]))->run(); 47 | $this->info("Transformer created successfully."); 48 | } catch (FileAlreadyExistsException $e) { 49 | $this->error($this->type . ' already exists!'); 50 | 51 | return false; 52 | } 53 | } 54 | 55 | 56 | /** 57 | * The array of command arguments. 58 | * 59 | * @return array 60 | */ 61 | public function getArguments() 62 | { 63 | return [ 64 | [ 65 | 'name', 66 | InputArgument::REQUIRED, 67 | 'The name of model for which the transformer is being generated.', 68 | null 69 | ], 70 | ]; 71 | } 72 | 73 | /** 74 | * The array of command options. 75 | * 76 | * @return array 77 | */ 78 | public function getOptions() 79 | { 80 | return [ 81 | [ 82 | 'force', 83 | 'f', 84 | InputOption::VALUE_NONE, 85 | 'Force the creation if file already exists.', 86 | null 87 | ] 88 | ]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Commands/ValidatorCommand.php: -------------------------------------------------------------------------------- 1 | $this->argument('name'), 46 | 'rules' => $this->option('rules'), 47 | 'force' => $this->option('force'), 48 | ]))->run(); 49 | $this->info("Validator created successfully."); 50 | } catch (FileAlreadyExistsException $e) { 51 | $this->error($this->type . ' already exists!'); 52 | 53 | return false; 54 | } 55 | } 56 | 57 | 58 | /** 59 | * The array of command arguments. 60 | * 61 | * @return array 62 | */ 63 | public function getArguments() 64 | { 65 | return [ 66 | [ 67 | 'name', 68 | InputArgument::REQUIRED, 69 | 'The name of model for which the validator is being generated.', 70 | null 71 | ], 72 | ]; 73 | } 74 | 75 | 76 | /** 77 | * The array of command options. 78 | * 79 | * @return array 80 | */ 81 | public function getOptions() 82 | { 83 | return [ 84 | [ 85 | 'rules', 86 | null, 87 | InputOption::VALUE_OPTIONAL, 88 | 'The rules of validation attributes.', 89 | null 90 | ], 91 | [ 92 | 'force', 93 | 'f', 94 | InputOption::VALUE_NONE, 95 | 'Force the creation if file already exists.', 96 | null 97 | ], 98 | ]; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/ControllerGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode())); 26 | } 27 | 28 | /** 29 | * Get generator path config node. 30 | * 31 | * @return string 32 | */ 33 | public function getPathConfigNode() 34 | { 35 | return 'controllers'; 36 | } 37 | 38 | /** 39 | * Get destination path for generated file. 40 | * 41 | * @return string 42 | */ 43 | public function getPath() 44 | { 45 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getControllerName() . 'Controller.php'; 46 | } 47 | 48 | /** 49 | * Get base path of destination file. 50 | * 51 | * @return string 52 | */ 53 | public function getBasePath() 54 | { 55 | return config('repository.generator.basePath', app_path()); 56 | } 57 | 58 | /** 59 | * Gets controller name based on model 60 | * 61 | * @return string 62 | */ 63 | public function getControllerName() 64 | { 65 | 66 | return ucfirst($this->getPluralName()); 67 | } 68 | 69 | /** 70 | * Gets plural name based on model 71 | * 72 | * @return string 73 | */ 74 | public function getPluralName() 75 | { 76 | 77 | return str_plural(lcfirst(ucwords($this->getClass()))); 78 | } 79 | 80 | /** 81 | * Get array replacements. 82 | * 83 | * @return array 84 | */ 85 | public function getReplacements() 86 | { 87 | 88 | return array_merge(parent::getReplacements(), [ 89 | 'controller' => $this->getControllerName(), 90 | 'plural' => $this->getPluralName(), 91 | 'singular' => $this->getSingularName(), 92 | 'validator' => $this->getValidator(), 93 | 'repository' => $this->getRepository(), 94 | 'appname' => $this->getAppNamespace(), 95 | ]); 96 | } 97 | 98 | /** 99 | * Gets singular name based on model 100 | * 101 | * @return string 102 | */ 103 | public function getSingularName() 104 | { 105 | return str_singular(lcfirst(ucwords($this->getClass()))); 106 | } 107 | 108 | /** 109 | * Gets validator full class name 110 | * 111 | * @return string 112 | */ 113 | public function getValidator() 114 | { 115 | $validatorGenerator = new ValidatorGenerator([ 116 | 'name' => $this->name, 117 | ]); 118 | 119 | $validator = $validatorGenerator->getRootNamespace() . '\\' . $validatorGenerator->getName(); 120 | 121 | return 'use ' . str_replace([ 122 | "\\", 123 | '/' 124 | ], '\\', $validator) . 'Validator;'; 125 | } 126 | 127 | 128 | /** 129 | * Gets repository full class name 130 | * 131 | * @return string 132 | */ 133 | public function getRepository() 134 | { 135 | $repositoryGenerator = new RepositoryInterfaceGenerator([ 136 | 'name' => $this->name, 137 | ]); 138 | 139 | $repository = $repositoryGenerator->getRootNamespace() . '\\' . $repositoryGenerator->getName(); 140 | 141 | return 'use ' . str_replace([ 142 | "\\", 143 | '/' 144 | ], '\\', $repository) . 'Repository;'; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/CriteriaGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 26 | } 27 | 28 | /** 29 | * Get generator path config node. 30 | * @return string 31 | */ 32 | public function getPathConfigNode() 33 | { 34 | return 'criteria'; 35 | } 36 | 37 | /** 38 | * Get destination path for generated file. 39 | * 40 | * @return string 41 | */ 42 | public function getPath() 43 | { 44 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . 'Criteria.php'; 45 | } 46 | 47 | /** 48 | * Get base path of destination file. 49 | * 50 | * @return string 51 | */ 52 | public function getBasePath() 53 | { 54 | return config('repository.generator.basePath', app_path()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/FileAlreadyExistsException.php: -------------------------------------------------------------------------------- 1 | filesystem = new Filesystem; 44 | $this->options = $options; 45 | } 46 | 47 | 48 | /** 49 | * Get the filesystem instance. 50 | * 51 | * @return \Illuminate\Filesystem\Filesystem 52 | */ 53 | public function getFilesystem() 54 | { 55 | return $this->filesystem; 56 | } 57 | 58 | 59 | /** 60 | * Set the filesystem instance. 61 | * 62 | * @param \Illuminate\Filesystem\Filesystem $filesystem 63 | * 64 | * @return $this 65 | */ 66 | public function setFilesystem(Filesystem $filesystem) 67 | { 68 | $this->filesystem = $filesystem; 69 | 70 | return $this; 71 | } 72 | 73 | 74 | /** 75 | * Get stub template for generated file. 76 | * 77 | * @return string 78 | */ 79 | public function getStub() 80 | { 81 | $path = config('repository.generator.stubsOverridePath', __DIR__); 82 | 83 | if(!file_exists($path . '/Stubs/' . $this->stub . '.stub')){ 84 | $path = __DIR__; 85 | } 86 | 87 | return (new Stub($path . '/Stubs/' . $this->stub . '.stub', $this->getReplacements()))->render(); 88 | } 89 | 90 | 91 | /** 92 | * Get template replacements. 93 | * 94 | * @return array 95 | */ 96 | public function getReplacements() 97 | { 98 | return [ 99 | 'class' => $this->getClass(), 100 | 'namespace' => $this->getNamespace(), 101 | 'root_namespace' => $this->getRootNamespace() 102 | ]; 103 | } 104 | 105 | 106 | /** 107 | * Get base path of destination file. 108 | * 109 | * @return string 110 | */ 111 | public function getBasePath() 112 | { 113 | return base_path(); 114 | } 115 | 116 | 117 | /** 118 | * Get destination path for generated file. 119 | * 120 | * @return string 121 | */ 122 | public function getPath() 123 | { 124 | return $this->getBasePath() . '/' . $this->getName() . '.php'; 125 | } 126 | 127 | 128 | /** 129 | * Get name input. 130 | * 131 | * @return string 132 | */ 133 | public function getName() 134 | { 135 | $name = $this->name; 136 | if (str_contains($this->name, '\\')) { 137 | $name = str_replace('\\', '/', $this->name); 138 | } 139 | if (str_contains($this->name, '/')) { 140 | $name = str_replace('/', '/', $this->name); 141 | } 142 | 143 | return Str::studly(str_replace(' ', '/', ucwords(str_replace('/', ' ', $name)))); 144 | } 145 | 146 | 147 | /** 148 | * Get class name. 149 | * 150 | * @return string 151 | */ 152 | public function getClass() 153 | { 154 | return Str::studly(class_basename($this->getName())); 155 | } 156 | 157 | 158 | /** 159 | * Get paths of namespace. 160 | * 161 | * @return array 162 | */ 163 | public function getSegments() 164 | { 165 | return explode('/', $this->getName()); 166 | } 167 | 168 | 169 | /** 170 | * Get root namespace. 171 | * 172 | * @return string 173 | */ 174 | public function getRootNamespace() 175 | { 176 | return config('repository.generator.rootNamespace', $this->getAppNamespace()); 177 | } 178 | 179 | 180 | /** 181 | * Get class-specific output paths. 182 | * 183 | * @param $class 184 | * 185 | * @return string 186 | */ 187 | public function getConfigGeneratorClassPath($class, $directoryPath = false) 188 | { 189 | switch ($class) { 190 | case ('models' === $class): 191 | $path = config('repository.generator.paths.models', 'Entities'); 192 | break; 193 | case ('repositories' === $class): 194 | $path = config('repository.generator.paths.repositories', 'Repositories'); 195 | break; 196 | case ('interfaces' === $class): 197 | $path = config('repository.generator.paths.interfaces', 'Repositories'); 198 | break; 199 | case ('presenters' === $class): 200 | $path = config('repository.generator.paths.presenters', 'Presenters'); 201 | break; 202 | case ('transformers' === $class): 203 | $path = config('repository.generator.paths.transformers', 'Transformers'); 204 | break; 205 | case ('validators' === $class): 206 | $path = config('repository.generator.paths.validators', 'Validators'); 207 | break; 208 | case ('controllers' === $class): 209 | $path = config('repository.generator.paths.controllers', 'Http\Controllers'); 210 | break; 211 | case ('provider' === $class): 212 | $path = config('repository.generator.paths.provider', 'RepositoryServiceProvider'); 213 | break; 214 | case ('criteria' === $class): 215 | $path = config('repository.generator.paths.criteria', 'Criteria'); 216 | break; 217 | default: 218 | $path = ''; 219 | } 220 | 221 | if ($directoryPath) { 222 | $path = str_replace('\\', '/', $path); 223 | } else { 224 | $path = str_replace('/', '\\', $path); 225 | } 226 | 227 | 228 | return $path; 229 | } 230 | 231 | 232 | abstract public function getPathConfigNode(); 233 | 234 | 235 | /** 236 | * Get class namespace. 237 | * 238 | * @return string 239 | */ 240 | public function getNamespace() 241 | { 242 | $segments = $this->getSegments(); 243 | array_pop($segments); 244 | $rootNamespace = $this->getRootNamespace(); 245 | if ($rootNamespace == false) { 246 | return null; 247 | } 248 | 249 | return 'namespace ' . rtrim($rootNamespace . '\\' . implode($segments, '\\'), '\\') . ';'; 250 | } 251 | 252 | 253 | /** 254 | * Setup some hook. 255 | * 256 | * @return void 257 | */ 258 | public function setUp() 259 | { 260 | // 261 | } 262 | 263 | 264 | /** 265 | * Run the generator. 266 | * 267 | * @return int 268 | * @throws FileAlreadyExistsException 269 | */ 270 | public function run() 271 | { 272 | $this->setUp(); 273 | if ($this->filesystem->exists($path = $this->getPath()) && !$this->force) { 274 | throw new FileAlreadyExistsException($path); 275 | } 276 | if (!$this->filesystem->isDirectory($dir = dirname($path))) { 277 | $this->filesystem->makeDirectory($dir, 0777, true, true); 278 | } 279 | 280 | return $this->filesystem->put($path, $this->getStub()); 281 | } 282 | 283 | 284 | /** 285 | * Get options. 286 | * 287 | * @return string 288 | */ 289 | public function getOptions() 290 | { 291 | return $this->options; 292 | } 293 | 294 | 295 | /** 296 | * Determinte whether the given key exist in options array. 297 | * 298 | * @param string $key 299 | * 300 | * @return boolean 301 | */ 302 | public function hasOption($key) 303 | { 304 | return array_key_exists($key, $this->options); 305 | } 306 | 307 | 308 | /** 309 | * Get value from options by given key. 310 | * 311 | * @param string $key 312 | * @param string|null $default 313 | * 314 | * @return string 315 | */ 316 | public function getOption($key, $default = null) 317 | { 318 | if (!$this->hasOption($key)) { 319 | return $default; 320 | } 321 | 322 | return $this->options[$key] ?: $default; 323 | } 324 | 325 | 326 | /** 327 | * Helper method for "getOption". 328 | * 329 | * @param string $key 330 | * @param string|null $default 331 | * 332 | * @return string 333 | */ 334 | public function option($key, $default = null) 335 | { 336 | return $this->getOption($key, $default); 337 | } 338 | 339 | 340 | /** 341 | * Handle call to __get method. 342 | * 343 | * @param string $key 344 | * 345 | * @return string|mixed 346 | */ 347 | public function __get($key) 348 | { 349 | if (property_exists($this, $key)) { 350 | return $this->{$key}; 351 | } 352 | 353 | return $this->option($key); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/MigrationGenerator.php: -------------------------------------------------------------------------------- 1 | getBasePath() . $this->getFileName() . '.php'; 43 | } 44 | 45 | 46 | /** 47 | * Get generator path config node. 48 | * 49 | * @return string 50 | */ 51 | public function getPathConfigNode() 52 | { 53 | return ''; 54 | } 55 | 56 | 57 | /** 58 | * Get root namespace. 59 | * 60 | * @return string 61 | */ 62 | public function getRootNamespace() 63 | { 64 | return ''; 65 | } 66 | 67 | 68 | /** 69 | * Get migration name. 70 | * 71 | * @return string 72 | */ 73 | public function getMigrationName() 74 | { 75 | return strtolower($this->name); 76 | } 77 | 78 | 79 | /** 80 | * Get file name. 81 | * 82 | * @return string 83 | */ 84 | public function getFileName() 85 | { 86 | return date('Y_m_d_His_') . $this->getMigrationName(); 87 | } 88 | 89 | 90 | /** 91 | * Get schema parser. 92 | * 93 | * @return SchemaParser 94 | */ 95 | public function getSchemaParser() 96 | { 97 | return new SchemaParser($this->fields); 98 | } 99 | 100 | 101 | /** 102 | * Get name parser. 103 | * 104 | * @return NameParser 105 | */ 106 | public function getNameParser() 107 | { 108 | return new NameParser($this->name); 109 | } 110 | 111 | 112 | /** 113 | * Get stub templates. 114 | * 115 | * @return string 116 | */ 117 | public function getStub() 118 | { 119 | $parser = $this->getNameParser(); 120 | 121 | $action = $parser->getAction(); 122 | switch ($action) { 123 | case 'add': 124 | case 'append': 125 | case 'update': 126 | case 'insert': 127 | $file = 'change'; 128 | $replacements = [ 129 | 'class' => $this->getClass(), 130 | 'table' => $parser->getTable(), 131 | 'fields_up' => $this->getSchemaParser()->up(), 132 | 'fields_down' => $this->getSchemaParser()->down(), 133 | ]; 134 | break; 135 | 136 | case 'delete': 137 | case 'remove': 138 | case 'alter': 139 | $file = 'change'; 140 | $replacements = [ 141 | 'class' => $this->getClass(), 142 | 'table' => $parser->getTable(), 143 | 'fields_down' => $this->getSchemaParser()->up(), 144 | 'fields_up' => $this->getSchemaParser()->down(), 145 | ]; 146 | break; 147 | default: 148 | $file = 'create'; 149 | $replacements = [ 150 | 'class' => $this->getClass(), 151 | 'table_singular' => str_singular($parser->getTable()), 152 | 'table' => $parser->getTable(), 153 | 'fields' => $this->getSchemaParser()->up(), 154 | ]; 155 | break; 156 | } 157 | $path = config('repository.generator.stubsOverridePath', __DIR__); 158 | 159 | if (!file_exists($path . "/Stubs/migration/{$file}.stub")) { 160 | $path = __DIR__; 161 | } 162 | 163 | if (!file_exists($path . "/Stubs/migration/{$file}.stub")) { 164 | throw new FileNotFoundException($path . "/Stubs/migration/{$file}.stub"); 165 | } 166 | 167 | return Stub::create($path . "/Stubs/migration/{$file}.stub", $replacements); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Migrations/NameParser.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'create', 30 | 'make' 31 | ], 32 | 'delete' => [ 33 | 'delete', 34 | 'remove' 35 | ], 36 | 'add' => [ 37 | 'add', 38 | 'update', 39 | 'append', 40 | 'insert' 41 | ], 42 | 'drop' => [ 43 | 'destroy', 44 | 'drop' 45 | ] 46 | ]; 47 | 48 | /** 49 | * The constructor. 50 | * 51 | * @param string $name 52 | */ 53 | public function __construct($name) 54 | { 55 | $this->name = $name; 56 | $this->data = $this->fetchData(); 57 | } 58 | 59 | /** 60 | * Fetch the migration name to an array data. 61 | * 62 | * @return array 63 | */ 64 | protected function fetchData() 65 | { 66 | return explode('_', $this->name); 67 | } 68 | 69 | /** 70 | * Get original migration name. 71 | * 72 | * @return string 73 | */ 74 | public function getOriginalName() 75 | { 76 | return $this->name; 77 | } 78 | 79 | /** 80 | * Get table name. 81 | * 82 | * @return string 83 | */ 84 | public function getTable() 85 | { 86 | return $this->getTableName(); 87 | } 88 | 89 | /** 90 | * Get the table will be used. 91 | * 92 | * @return string 93 | */ 94 | public function getTableName() 95 | { 96 | $matches = array_reverse($this->getMatches()); 97 | 98 | return array_shift($matches); 99 | } 100 | 101 | /** 102 | * Get matches data from regex. 103 | * 104 | * @return array 105 | */ 106 | public function getMatches() 107 | { 108 | preg_match($this->getPattern(), $this->name, $matches); 109 | 110 | return $matches; 111 | } 112 | 113 | /** 114 | * Get name pattern. 115 | * 116 | * @return string 117 | */ 118 | public function getPattern() 119 | { 120 | switch ($action = $this->getAction()) { 121 | case 'add': 122 | case 'append': 123 | case 'update': 124 | case 'insert': 125 | return "/{$action}_(.*)_to_(.*)_table/"; 126 | break; 127 | 128 | case 'delete': 129 | case 'remove': 130 | case 'alter': 131 | return "/{$action}_(.*)_from_(.*)_table/"; 132 | break; 133 | default: 134 | return "/{$action}_(.*)_table/"; 135 | break; 136 | } 137 | } 138 | 139 | /** 140 | * Get schema type or action. 141 | * 142 | * @return string 143 | */ 144 | public function getAction() 145 | { 146 | return head($this->data); 147 | } 148 | 149 | /** 150 | * Get the array data. 151 | * 152 | * @return array 153 | */ 154 | public function getData() 155 | { 156 | return $this->data; 157 | } 158 | 159 | /** 160 | * Determine whether the given type is same with the current schema action or type. 161 | * 162 | * @param $type 163 | * 164 | * @return bool 165 | */ 166 | public function is($type) 167 | { 168 | return $type == $this->getAction(); 169 | } 170 | 171 | /** 172 | * Determine whether the current schema action is a adding action. 173 | * 174 | * @return bool 175 | */ 176 | public function isAdd() 177 | { 178 | return in_array($this->getAction(), $this->actions['add']); 179 | } 180 | 181 | /** 182 | * Determine whether the current schema action is a deleting action. 183 | * 184 | * @return bool 185 | */ 186 | public function isDelete() 187 | { 188 | return in_array($this->getAction(), $this->actions['delete']); 189 | } 190 | 191 | /** 192 | * Determine whether the current schema action is a creating action. 193 | * 194 | * @return bool 195 | */ 196 | public function isCreate() 197 | { 198 | return in_array($this->getAction(), $this->actions['create']); 199 | } 200 | 201 | /** 202 | * Determine whether the current schema action is a dropping action. 203 | * 204 | * @return bool 205 | */ 206 | public function isDrop() 207 | { 208 | return in_array($this->getAction(), $this->actions['drop']); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Migrations/RulesParser.php: -------------------------------------------------------------------------------- 1 | rules = $rules; 29 | } 30 | 31 | /** 32 | * Convert string migration to array. 33 | * 34 | * @return array 35 | */ 36 | public function toArray() 37 | { 38 | return $this->parse($this->rules); 39 | } 40 | 41 | /** 42 | * Parse a string to array of formatted rules. 43 | * 44 | * @param string $rules 45 | * 46 | * @return array 47 | */ 48 | public function parse($rules) 49 | { 50 | $this->rules = $rules; 51 | $parsed = []; 52 | foreach ($this->getRules() as $rulesArray) { 53 | $column = $this->getColumn($rulesArray); 54 | $attributes = $this->getAttributes($column, $rulesArray); 55 | $parsed[$column] = $attributes; 56 | } 57 | 58 | return $parsed; 59 | } 60 | 61 | /** 62 | * Get array of rules. 63 | * 64 | * @return array 65 | */ 66 | public function getRules() 67 | { 68 | if (is_null($this->rules)) { 69 | return []; 70 | } 71 | 72 | return explode(',', str_replace(' ', '', $this->rules)); 73 | } 74 | 75 | /** 76 | * Get column name from rules. 77 | * 78 | * @param string $rules 79 | * 80 | * @return string 81 | */ 82 | public function getColumn($rules) 83 | { 84 | return array_first(explode('=>', $rules), function ($key, $value) { 85 | return $value; 86 | }); 87 | } 88 | 89 | 90 | /** 91 | * Get column attributes. 92 | * 93 | * @param string $column 94 | * @param string $rules 95 | * 96 | * @return array 97 | */ 98 | public function getAttributes($column, $rules) 99 | { 100 | 101 | return str_replace($column . '=>', '', $rules); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Migrations/SchemaParser.php: -------------------------------------------------------------------------------- 1 | 'rememberToken()', 19 | 'soft_delete' => 'softDeletes()', 20 | ]; 21 | /** 22 | * The migration schema. 23 | * 24 | * @var string 25 | */ 26 | protected $schema; 27 | 28 | /** 29 | * Create new instance. 30 | * 31 | * @param string|null $schema 32 | */ 33 | public function __construct($schema = null) 34 | { 35 | $this->schema = $schema; 36 | } 37 | 38 | /** 39 | * Render up migration fields. 40 | * 41 | * @return string 42 | */ 43 | public function up() 44 | { 45 | return $this->render(); 46 | } 47 | 48 | /** 49 | * Render the migration to formatted script. 50 | * 51 | * @return string 52 | */ 53 | public function render() 54 | { 55 | $results = ''; 56 | foreach ($this->toArray() as $column => $attributes) { 57 | $results .= $this->createField($column, $attributes); 58 | } 59 | 60 | return $results; 61 | } 62 | 63 | /** 64 | * Convert string migration to array. 65 | * 66 | * @return array 67 | */ 68 | public function toArray() 69 | { 70 | return $this->parse($this->schema); 71 | } 72 | 73 | /** 74 | * Parse a string to array of formatted schema. 75 | * 76 | * @param string $schema 77 | * 78 | * @return array 79 | */ 80 | public function parse($schema) 81 | { 82 | $this->schema = $schema; 83 | $parsed = []; 84 | foreach ($this->getSchemas() as $schemaArray) { 85 | $column = $this->getColumn($schemaArray); 86 | $attributes = $this->getAttributes($column, $schemaArray); 87 | $parsed[$column] = $attributes; 88 | } 89 | 90 | return $parsed; 91 | } 92 | 93 | /** 94 | * Get array of schema. 95 | * 96 | * @return array 97 | */ 98 | public function getSchemas() 99 | { 100 | if (is_null($this->schema)) { 101 | return []; 102 | } 103 | 104 | return explode(',', str_replace(' ', '', $this->schema)); 105 | } 106 | 107 | /** 108 | * Get column name from schema. 109 | * 110 | * @param string $schema 111 | * 112 | * @return string 113 | */ 114 | public function getColumn($schema) 115 | { 116 | return array_first(explode(':', $schema), function ($key, $value) { 117 | return $value; 118 | }); 119 | } 120 | 121 | /** 122 | * Get column attributes. 123 | * 124 | * @param string $column 125 | * @param string $schema 126 | * 127 | * @return array 128 | */ 129 | public function getAttributes($column, $schema) 130 | { 131 | $fields = str_replace($column . ':', '', $schema); 132 | 133 | return $this->hasCustomAttribute($column) ? $this->getCustomAttribute($column) : explode(':', $fields); 134 | } 135 | 136 | /** 137 | * Determinte whether the given column is exist in customAttributes array. 138 | * 139 | * @param string $column 140 | * 141 | * @return boolean 142 | */ 143 | public function hasCustomAttribute($column) 144 | { 145 | return array_key_exists($column, $this->customAttributes); 146 | } 147 | 148 | /** 149 | * Get custom attributes value. 150 | * 151 | * @param string $column 152 | * 153 | * @return array 154 | */ 155 | public function getCustomAttribute($column) 156 | { 157 | return (array)$this->customAttributes[$column]; 158 | } 159 | 160 | /** 161 | * Create field. 162 | * 163 | * @param string $column 164 | * @param array $attributes 165 | * 166 | * @return string 167 | */ 168 | public function createField($column, $attributes, $type = 'add') 169 | { 170 | $results = "\t\t\t" . '$table'; 171 | foreach ($attributes as $key => $field) { 172 | $results .= $this->{"{$type}Column"}($key, $field, $column); 173 | } 174 | 175 | return $results .= ';' . PHP_EOL; 176 | } 177 | 178 | /** 179 | * Render down migration fields. 180 | * 181 | * @return string 182 | */ 183 | public function down() 184 | { 185 | $results = ''; 186 | foreach ($this->toArray() as $column => $attributes) { 187 | $results .= $this->createField($column, $attributes, 'remove'); 188 | } 189 | 190 | return $results; 191 | } 192 | 193 | /** 194 | * Format field to script. 195 | * 196 | * @param int $key 197 | * @param string $field 198 | * @param string $column 199 | * 200 | * @return string 201 | */ 202 | protected function addColumn($key, $field, $column) 203 | { 204 | if ($this->hasCustomAttribute($column)) { 205 | return '->' . $field; 206 | } 207 | if ($key == 0) { 208 | return '->' . $field . "('" . $column . "')"; 209 | } 210 | if (str_contains($field, '(')) { 211 | return '->' . $field; 212 | } 213 | 214 | return '->' . $field . '()'; 215 | } 216 | 217 | /** 218 | * Format field to script. 219 | * 220 | * @param int $key 221 | * @param string $field 222 | * @param string $column 223 | * 224 | * @return string 225 | */ 226 | protected function removeColumn($key, $field, $column) 227 | { 228 | if ($this->hasCustomAttribute($column)) { 229 | return '->' . $field; 230 | } 231 | 232 | return '->dropColumn(' . "'" . $column . "')"; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/ModelGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 29 | } 30 | 31 | /** 32 | * Get generator path config node. 33 | * 34 | * @return string 35 | */ 36 | public function getPathConfigNode() 37 | { 38 | return 'models'; 39 | } 40 | 41 | /** 42 | * Get destination path for generated file. 43 | * 44 | * @return string 45 | */ 46 | public function getPath() 47 | { 48 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . '.php'; 49 | } 50 | 51 | /** 52 | * Get base path of destination file. 53 | * 54 | * @return string 55 | */ 56 | 57 | public function getBasePath() 58 | { 59 | return config('repository.generator.basePath', app_path()); 60 | } 61 | 62 | /** 63 | * Get array replacements. 64 | * 65 | * @return array 66 | */ 67 | public function getReplacements() 68 | { 69 | return array_merge(parent::getReplacements(), [ 70 | 'fillable' => $this->getFillable(), 71 | 'use_base_model' => 'use ' . $this->getRootNamespace() . '\BaseModel;', 72 | ]); 73 | } 74 | 75 | /** 76 | * Get the fillable attributes. 77 | * 78 | * @return string 79 | */ 80 | public function getFillable() 81 | { 82 | if (!$this->fillable) { 83 | return '[]'; 84 | } 85 | $results = '[' . PHP_EOL; 86 | 87 | foreach ($this->getSchemaParser()->toArray() as $column => $value) { 88 | $results .= "\t\t'{$column}'," . PHP_EOL; 89 | } 90 | 91 | return $results . "\t" . ']'; 92 | } 93 | 94 | /** 95 | * Get schema parser. 96 | * 97 | * @return SchemaParser 98 | */ 99 | public function getSchemaParser() 100 | { 101 | return new SchemaParser($this->fillable); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/PresenterGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 26 | } 27 | 28 | /** 29 | * Get generator path config node. 30 | * 31 | * @return string 32 | */ 33 | public function getPathConfigNode() 34 | { 35 | return 'presenters'; 36 | } 37 | 38 | /** 39 | * Get array replacements. 40 | * 41 | * @return array 42 | */ 43 | public function getReplacements() 44 | { 45 | $transformerGenerator = new TransformerGenerator([ 46 | 'name' => $this->name 47 | ]); 48 | $transformer = $transformerGenerator->getRootNamespace() . '\\' . $transformerGenerator->getName() . 'Transformer'; 49 | $transformer = str_replace([ 50 | "\\", 51 | '/' 52 | ], '\\', $transformer); 53 | echo $transformer; 54 | 55 | return array_merge(parent::getReplacements(), [ 56 | 'transformer' => $transformer 57 | ]); 58 | } 59 | 60 | /** 61 | * Get destination path for generated file. 62 | * 63 | * @return string 64 | */ 65 | public function getPath() 66 | { 67 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . 'Presenter.php'; 68 | } 69 | 70 | /** 71 | * Get base path of destination file. 72 | * 73 | * @return string 74 | */ 75 | public function getBasePath() 76 | { 77 | return config('repository.generator.basePath', app_path()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/RepositoryEloquentGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 28 | } 29 | 30 | /** 31 | * Get generator path config node. 32 | * 33 | * @return string 34 | */ 35 | public function getPathConfigNode() 36 | { 37 | return 'repositories'; 38 | } 39 | 40 | /** 41 | * Get destination path for generated file. 42 | * 43 | * @return string 44 | */ 45 | public function getPath() 46 | { 47 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . 'RepositoryEloquent.php'; 48 | } 49 | 50 | /** 51 | * Get base path of destination file. 52 | * 53 | * @return string 54 | */ 55 | public function getBasePath() 56 | { 57 | return config('repository.generator.basePath', app_path()); 58 | } 59 | 60 | /** 61 | * Get array replacements. 62 | * 63 | * @return array 64 | */ 65 | public function getReplacements() 66 | { 67 | $repository = parent::getRootNamespace() . parent::getConfigGeneratorClassPath('interfaces') . '\\' . $this->name . 'Repository;'; 68 | $repository = str_replace([ 69 | "\\", 70 | '/' 71 | ], '\\', $repository); 72 | 73 | return array_merge(parent::getReplacements(), [ 74 | 'fillable' => $this->getFillable(), 75 | 'use_validator' => $this->getValidatorUse(), 76 | 'validator' => $this->getValidatorMethod(), 77 | 'use_presenter' => $this->getPresenterUse(), 78 | 'root_namespace' => parent::getRootNamespace(), 79 | 'presenter' => $this->getPresenterMethod(), 80 | 'repository' => $repository, 81 | 'model' => isset($this->options['model']) ? $this->options['model'] : '' 82 | ]); 83 | } 84 | 85 | /** 86 | * Get the fillable attributes. 87 | * 88 | * @return string 89 | */ 90 | public function getFillable() 91 | { 92 | if (!$this->fillable) { 93 | return '[]'; 94 | } 95 | $results = '[' . PHP_EOL; 96 | 97 | foreach ($this->getSchemaParser()->toArray() as $column => $value) { 98 | $results .= "\t\t'{$column}'," . PHP_EOL; 99 | } 100 | 101 | return $results . "\t" . ']'; 102 | } 103 | 104 | /** 105 | * Get schema parser. 106 | * 107 | * @return SchemaParser 108 | */ 109 | public function getSchemaParser() 110 | { 111 | return new SchemaParser($this->fillable); 112 | } 113 | 114 | public function getValidatorUse() 115 | { 116 | $validator = $this->getValidator(); 117 | 118 | return "use {$validator};"; 119 | } 120 | 121 | 122 | public function getValidator() 123 | { 124 | $validatorGenerator = new ValidatorGenerator([ 125 | 'name' => $this->name, 126 | 'rules' => $this->rules, 127 | 'force' => $this->force, 128 | ]); 129 | 130 | $validator = $validatorGenerator->getRootNamespace() . '\\' . $validatorGenerator->getName(); 131 | 132 | return str_replace([ 133 | "\\", 134 | '/' 135 | ], '\\', $validator) . 'Validator'; 136 | 137 | } 138 | 139 | 140 | public function getValidatorMethod() 141 | { 142 | if ($this->validator != 'yes') { 143 | return ''; 144 | } 145 | 146 | $class = $this->getClass(); 147 | 148 | return '/**' . PHP_EOL . ' * Specify Validator class name' . PHP_EOL . ' *' . PHP_EOL . ' * @return mixed' . PHP_EOL . ' */' . PHP_EOL . ' public function validator()' . PHP_EOL . ' {' . PHP_EOL . PHP_EOL . ' return ' . $class . 'Validator::class;' . PHP_EOL . ' }' . PHP_EOL; 149 | 150 | } 151 | 152 | public function getPresenterUse() 153 | { 154 | $presenter = $this->getPresenter(); 155 | 156 | return "use {$presenter};"; 157 | } 158 | 159 | public function getPresenter() 160 | { 161 | $presenterGenerator = new PresenterGenerator([ 162 | 'name' => $this->name, 163 | 'rules' => $this->rules, 164 | 'force' => $this->force, 165 | ]); 166 | 167 | $presenter = $presenterGenerator->getRootNamespace() . '\\' . $presenterGenerator->getName(); 168 | 169 | return str_replace([ 170 | "\\", 171 | '/' 172 | ], '\\', $presenter) . 'Presenter'; 173 | 174 | } 175 | 176 | public function getPresenterMethod() 177 | { 178 | if ($this->presenter != 'yes') { 179 | return ''; 180 | } 181 | 182 | $class = $this->getClass(); 183 | 184 | return '/**' . PHP_EOL . ' * Specify Presenter class name' . PHP_EOL . ' *' . PHP_EOL . ' * @return mixed' . PHP_EOL . ' */' . PHP_EOL . ' public function presenter()' . PHP_EOL . ' {' . PHP_EOL . PHP_EOL . ' return ' . $class . 'Presenter::class;' . PHP_EOL . ' }' . PHP_EOL; 185 | 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/RepositoryInterfaceGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 29 | } 30 | 31 | /** 32 | * Get generator path config node. 33 | * 34 | * @return string 35 | */ 36 | public function getPathConfigNode() 37 | { 38 | return 'interfaces'; 39 | } 40 | 41 | /** 42 | * Get destination path for generated file. 43 | * 44 | * @return string 45 | */ 46 | public function getPath() 47 | { 48 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . 'Repository.php'; 49 | } 50 | 51 | /** 52 | * Get base path of destination file. 53 | * 54 | * @return string 55 | */ 56 | public function getBasePath() 57 | { 58 | return config('repository.generator.basePath', app_path()); 59 | } 60 | 61 | /** 62 | * Get array replacements. 63 | * 64 | * @return array 65 | */ 66 | public function getReplacements() 67 | { 68 | return array_merge(parent::getReplacements(), [ 69 | 'fillable' => $this->getFillable() 70 | ]); 71 | } 72 | 73 | /** 74 | * Get the fillable attributes. 75 | * 76 | * @return string 77 | */ 78 | public function getFillable() 79 | { 80 | if (!$this->fillable) { 81 | return '[]'; 82 | } 83 | $results = '[' . PHP_EOL; 84 | 85 | foreach ($this->getSchemaParser()->toArray() as $column => $value) { 86 | $results .= "\t\t'{$column}'," . PHP_EOL; 87 | } 88 | 89 | return $results . "\t" . ']'; 90 | } 91 | 92 | /** 93 | * Get schema parser. 94 | * 95 | * @return SchemaParser 96 | */ 97 | public function getSchemaParser() 98 | { 99 | return new SchemaParser($this->fillable); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stub.php: -------------------------------------------------------------------------------- 1 | path = $path; 39 | $this->replaces = $replaces; 40 | } 41 | 42 | /** 43 | * Create new self instance. 44 | * 45 | * @param string $path 46 | * @param array $replaces 47 | * 48 | * @return self 49 | */ 50 | public static function create($path, array $replaces = []) 51 | { 52 | return new static($path, $replaces); 53 | } 54 | 55 | /** 56 | * Set base path. 57 | * 58 | * @param string $path 59 | * 60 | * @return void 61 | */ 62 | public static function setBasePath($path) 63 | { 64 | static::$basePath = $path; 65 | } 66 | 67 | /** 68 | * Set replacements array. 69 | * 70 | * @param array $replaces 71 | * 72 | * @return $this 73 | */ 74 | public function replace(array $replaces = []) 75 | { 76 | $this->replaces = $replaces; 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * Get replacements. 83 | * 84 | * @return array 85 | */ 86 | public function getReplaces() 87 | { 88 | return $this->replaces; 89 | } 90 | 91 | /** 92 | * Handle magic method __toString. 93 | * 94 | * @return string 95 | */ 96 | public function __toString() 97 | { 98 | return $this->render(); 99 | } 100 | 101 | /** 102 | * Get stub contents. 103 | * 104 | * @return string 105 | */ 106 | public function render() 107 | { 108 | return $this->getContents(); 109 | } 110 | 111 | /** 112 | * Get stub contents. 113 | * 114 | * @return mixed|string 115 | */ 116 | public function getContents() 117 | { 118 | $contents = file_get_contents($this->getPath()); 119 | foreach ($this->replaces as $search => $replace) { 120 | $contents = str_replace('$' . strtoupper($search) . '$', $replace, $contents); 121 | } 122 | 123 | return $contents; 124 | } 125 | 126 | /** 127 | * Get stub path. 128 | * 129 | * @return string 130 | */ 131 | public function getPath() 132 | { 133 | return static::$basePath . $this->path; 134 | } 135 | 136 | /** 137 | * Set stub path. 138 | * 139 | * @param string $path 140 | * 141 | * @return self 142 | */ 143 | public function setPath($path) 144 | { 145 | $this->path = $path; 146 | 147 | return $this; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/bindings/bindings.stub: -------------------------------------------------------------------------------- 1 | 2 | $this->app->bind($REPOSITORY$, $ELOQUENT$); 3 | $PLACEHOLDER$ -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/controller/controller.stub: -------------------------------------------------------------------------------- 1 | repository = $repository; 31 | $this->validator = $validator; 32 | } 33 | 34 | /** 35 | * Display a listing of the resource. 36 | * 37 | * @param Request $request 38 | * @return \Illuminate\Http\Response 39 | */ 40 | public function index(Request $request) 41 | { 42 | return $this->repository->paginate(); 43 | } 44 | 45 | /** 46 | * Display all resources. 47 | * 48 | * @param Request $request 49 | * @return \Illuminate\Http\Response 50 | */ 51 | public function all(Request $request) 52 | { 53 | return $this->repository->all(); 54 | } 55 | 56 | /** 57 | * Store a newly created resource in storage. 58 | * 59 | * @param $CLASS$CreateRequest $request 60 | * 61 | * @return \Illuminate\Http\Response 62 | */ 63 | public function store($CLASS$CreateRequest $request) 64 | { 65 | 66 | $data = $request->all(); 67 | 68 | $this->validator->with($data)->passesOrFail(ValidatorInterface::RULE_CREATE); 69 | 70 | $$SINGULAR$ = $this->repository->create($data); 71 | 72 | // throw exception if store failed 73 | // throw new StoreResourceFailedException('Failed to store.'); 74 | 75 | // A. return 201 created 76 | // return $this->response->created(null); 77 | 78 | // B. return data 79 | return $$SINGULAR$; 80 | 81 | } 82 | 83 | 84 | /** 85 | * Display the specified resource. 86 | * 87 | * @param int $id 88 | * 89 | * @return \Illuminate\Http\Response 90 | */ 91 | public function show($id) 92 | { 93 | return $this->repository->find($id); 94 | } 95 | 96 | /** 97 | * Update the specified resource in storage. 98 | * 99 | * @param $CLASS$UpdateRequest $request 100 | * @param string $id 101 | * 102 | * @return Response 103 | */ 104 | public function update($CLASS$UpdateRequest $request, $id) 105 | { 106 | 107 | $data = $request->all(); 108 | 109 | $this->validator->with($data)->passesOrFail(ValidatorInterface::RULE_UPDATE); 110 | 111 | $$SINGULAR$ = $this->repository->update($data, $id); 112 | 113 | // throw exception if update failed 114 | // throw new UpdateResourceFailedException('Failed to update.'); 115 | 116 | // Updated, return 204 No Content 117 | return $this->response->noContent(); 118 | 119 | } 120 | 121 | 122 | /** 123 | * Remove the specified resource from storage. 124 | * 125 | * @param int $id 126 | * 127 | * @return \Illuminate\Http\Response 128 | */ 129 | public function destroy($id) 130 | { 131 | $deleted = $this->repository->delete($id); 132 | 133 | if ($deleted) { 134 | // Deleted, return 204 No Content 135 | return $this->response->noContent(); 136 | } else { 137 | // Failed, throw exception 138 | throw new DeleteResourceFailedException('Failed to delete.'); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/criteria/criteria.stub: -------------------------------------------------------------------------------- 1 | increments('$TABLE_SINGULAR$_id'); 18 | $table->unsignedInteger('user_id')->index(); 19 | 20 | // Adding more table related fields here... 21 | $FIELDS$ 22 | 23 | $table->unsignedInteger('created_by')->nullable(); 24 | $table->timestamp('created_at')->nullable(); 25 | $table->ipAddress('created_ip')->nullable(); 26 | $table->unsignedInteger('updated_by')->nullable(); 27 | $table->timestamp('updated_at')->nullable(); 28 | $table->ipAddress('updated_ip')->nullable(); 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | * 35 | * @return void 36 | */ 37 | public function down() 38 | { 39 | Schema::drop('$TABLE$'); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/model.stub: -------------------------------------------------------------------------------- 1 | pushCriteria(app(RequestCriteria::class)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/repository/interface.stub: -------------------------------------------------------------------------------- 1 | call("OthersTableSeeder"); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/transformer/transformer.stub: -------------------------------------------------------------------------------- 1 | (int) $model->id, 24 | 25 | /* place your other model properties here */ 26 | 27 | 'created_at' => (string) $model->created_at, 28 | 'updated_at' => (string) $model->updated_at 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/Stubs/validator/validator.stub: -------------------------------------------------------------------------------- 1 | $RULES$, 13 | ValidatorInterface::RULE_UPDATE => $RULES$, 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/TransformerGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 26 | } 27 | 28 | /** 29 | * Get generator path config node. 30 | * 31 | * @return string 32 | */ 33 | public function getPathConfigNode() 34 | { 35 | return 'transformers'; 36 | } 37 | 38 | /** 39 | * Get destination path for generated file. 40 | * 41 | * @return string 42 | */ 43 | public function getPath() 44 | { 45 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . 'Transformer.php'; 46 | } 47 | 48 | /** 49 | * Get base path of destination file. 50 | * 51 | * @return string 52 | */ 53 | public function getBasePath() 54 | { 55 | return config('repository.generator.basePath', app_path()); 56 | } 57 | 58 | /** 59 | * Get array replacements. 60 | * 61 | * @return array 62 | */ 63 | public function getReplacements() 64 | { 65 | $modelGenerator = new ModelGenerator([ 66 | 'name' => $this->name 67 | ]); 68 | $model = $modelGenerator->getRootNamespace() . '\\' . $modelGenerator->getName(); 69 | $model = str_replace([ 70 | "\\", 71 | '/' 72 | ], '\\', $model); 73 | 74 | return array_merge(parent::getReplacements(), [ 75 | 'model' => $model 76 | ]); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Someline/Repository/Generators/ValidatorGenerator.php: -------------------------------------------------------------------------------- 1 | getPathConfigNode()); 29 | } 30 | 31 | /** 32 | * Get generator path config node. 33 | * 34 | * @return string 35 | */ 36 | public function getPathConfigNode() 37 | { 38 | return 'validators'; 39 | } 40 | 41 | /** 42 | * Get destination path for generated file. 43 | * 44 | * @return string 45 | */ 46 | public function getPath() 47 | { 48 | return $this->getBasePath() . '/' . parent::getConfigGeneratorClassPath($this->getPathConfigNode(), true) . '/' . $this->getName() . 'Validator.php'; 49 | } 50 | 51 | /** 52 | * Get base path of destination file. 53 | * 54 | * @return string 55 | */ 56 | public function getBasePath() 57 | { 58 | return config('repository.generator.basePath', app_path()); 59 | } 60 | 61 | /** 62 | * Get array replacements. 63 | * 64 | * @return array 65 | */ 66 | public function getReplacements() 67 | { 68 | 69 | return array_merge(parent::getReplacements(), [ 70 | 'rules' => $this->getRules(), 71 | ]); 72 | } 73 | 74 | /** 75 | * Get the rules. 76 | * 77 | * @return string 78 | */ 79 | public function getRules() 80 | { 81 | if (!$this->rules) { 82 | return '[]'; 83 | } 84 | $results = '[' . PHP_EOL; 85 | 86 | foreach ($this->getSchemaParser()->toArray() as $column => $value) { 87 | $results .= "\t\t'{$column}'\t=>'\t{$value}'," . PHP_EOL; 88 | } 89 | 90 | return $results . "\t" . ']'; 91 | } 92 | 93 | /** 94 | * Get schema parser. 95 | * 96 | * @return SchemaParser 97 | */ 98 | public function getSchemaParser() 99 | { 100 | return new RulesParser($this->rules); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Someline/Repository/Providers/RepositoryServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom(base_path('vendor/prettus/l5-repository/src/resources/config/repository.php'), 'repository'); 28 | 29 | $this->loadTranslationsFrom(base_path('vendor/prettus/l5-repository/src/resources/lang'), 'repository'); 30 | } 31 | 32 | 33 | /** 34 | * Register the service provider. 35 | * 36 | * @return void 37 | */ 38 | public function register() 39 | { 40 | $this->commands('Someline\Repository\Generators\Commands\RepositoryCommand'); 41 | $this->commands('Someline\Repository\Generators\Commands\TransformerCommand'); 42 | $this->commands('Someline\Repository\Generators\Commands\PresenterCommand'); 43 | $this->commands('Someline\Repository\Generators\Commands\EntityCommand'); 44 | $this->commands('Someline\Repository\Generators\Commands\ValidatorCommand'); 45 | $this->commands('Someline\Repository\Generators\Commands\ControllerCommand'); 46 | $this->commands('Someline\Repository\Generators\Commands\BindingsCommand'); 47 | $this->commands('Someline\Repository\Generators\Commands\CriteriaCommand'); 48 | } 49 | 50 | 51 | /** 52 | * Get the services provided by the provider. 53 | * 54 | * @return array 55 | */ 56 | public function provides() 57 | { 58 | return []; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Someline/Support/Controllers/LocaleController.php: -------------------------------------------------------------------------------- 1 | make($content); 24 | $response->header('Content-Type', 'application/javascript'); 25 | $response->setPublic() 26 | ->setMaxAge(604800) 27 | ->setExpires(Carbon::now()->addDay(7)); 28 | return $response; 29 | } 30 | 31 | /** 32 | * @param Request $request 33 | * @param $locale 34 | * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector 35 | */ 36 | public function getSwitchLocale(Request $request, $locale) 37 | { 38 | // check if supported 39 | $supportedLanguagesKeys = \LaravelLocalization::getSupportedLanguagesKeys(); 40 | if (!in_array($locale, $supportedLanguagesKeys)) { 41 | abort(404); 42 | } 43 | 44 | // store in session 45 | session(['someline-locale' => $locale]); 46 | 47 | // check if has redirect url 48 | $redirect_url = '/'; 49 | if ($request->has('redirect_url')) { 50 | $redirect_url = $request->get('redirect_url'); 51 | } 52 | return redirect($redirect_url); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/Someline/Support/Middleware/LocaleMiddleware.php: -------------------------------------------------------------------------------- 1 | get('lang'); 38 | if (!empty($lang)) { 39 | // if supported 40 | if (is_array($supportedLocales) && isset($supportedLocales[$lang])) { 41 | $locale = $lang; 42 | } 43 | } 44 | 45 | // set locale 46 | LaravelLocalization::setLocale($locale); 47 | 48 | // set carbon locale 49 | Carbon::setLocale($locale); 50 | 51 | return $next($request); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/Someline/Transformers/BasicTransformer.php: -------------------------------------------------------------------------------- 1 |