├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml └── workflows │ ├── monorepo-split.yml │ ├── monorepo-validate.yml │ ├── php-cs-fixer.yml │ └── tests.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── composer.json ├── monorepo-builder.php ├── packages ├── airlines-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── AirlinesEnServiceProvider.php ├── airlines │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── AirlinesServiceProvider.php │ │ ├── Models │ │ └── Airline.php │ │ └── Rules │ │ └── AirlineRule.php ├── airports-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── AirportsEnServiceProvider.php ├── airports │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── AirportsServiceProvider.php │ │ ├── Models │ │ └── Airport.php │ │ └── Rules │ │ └── AirportRule.php ├── continents-de │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── ContinentsDeServiceProvider.php ├── continents-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── ContinentsEnServiceProvider.php ├── continents-pl │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── ContinentsPlServiceProvider.php ├── continents │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── ContinentsServiceProvider.php │ │ ├── Models │ │ └── Continent.php │ │ └── Rules │ │ └── ContinentRule.php ├── countries-de │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── CountriesDeServiceProvider.php ├── countries-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── CountriesEnServiceProvider.php ├── countries-es │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── CountriesEsServiceProvider.php ├── countries-fr │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── CountriesFrServiceProvider.php ├── countries-pl │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── CountriesPlServiceProvider.php ├── countries │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── CountriesServiceProvider.php │ │ ├── Models │ │ └── Country.php │ │ └── Rules │ │ └── CountryRule.php ├── currencies-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── CurrenciesEnServiceProvider.php ├── currencies │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── CurrenciesServiceProvider.php │ │ ├── Models │ │ └── Currency.php │ │ └── Rules │ │ └── CurrencyRule.php ├── gb-counties-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── GbCountiesEnServiceProvider.php ├── gb-counties │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── GbCountiesServiceProvider.php │ │ ├── Models │ │ └── GbCounty.php │ │ └── Rules │ │ └── GbCountyRule.php ├── model │ ├── composer.json │ ├── config │ │ └── squire.php │ └── src │ │ ├── Model.php │ │ └── ModelServiceProvider.php ├── regions-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── RegionsEnServiceProvider.php ├── regions │ ├── composer.json │ ├── resources │ │ └── lang │ │ │ └── en │ │ │ └── validation.php │ └── src │ │ ├── Models │ │ └── Region.php │ │ ├── RegionsServiceProvider.php │ │ └── Rules │ │ └── RegionRule.php ├── repository │ ├── composer.json │ └── src │ │ ├── Exceptions │ │ ├── SourceNotFoundException.php │ │ └── TranslationNotFoundException.php │ │ ├── Repository.php │ │ ├── RepositoryManager.php │ │ └── RepositoryServiceProvider.php ├── rule │ ├── composer.json │ └── src │ │ └── Rule.php ├── timezones-en │ ├── composer.json │ ├── resources │ │ └── data.csv │ └── src │ │ └── TimezonesEnServiceProvider.php └── timezones │ ├── composer.json │ ├── resources │ └── lang │ │ └── en │ │ └── validation.php │ └── src │ ├── Models │ └── Timezone.php │ ├── Rules │ └── TimezoneRule.php │ └── TimezonesServiceProvider.php ├── phpunit.xml.dist └── tests ├── ModelTest.php ├── Models └── Foo.php ├── RuleTest.php ├── Rules └── FooRule.php ├── TestCase.php ├── TranslationsConsistencyTest.php └── data ├── foo-en.csv └── foo-es.csv /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [danharrin] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: bug 5 | assignees: DanHarrin 6 | --- 7 | 8 | **Describe the bug** 9 | A clear and concise description of what the bug is. 10 | 11 | **To reproduce** 12 | A simplified code example to demonstrate the issue you are facing. 13 | 14 | **Expected behavior** 15 | A clear and concise description of what you expected to happen. 16 | 17 | **Context** 18 | - Squire version: [e.g. 2.0.0] 19 | - Laravel version: [e.g. 8.0.0] 20 | - Server OS: [e.g. Ubuntu 18.04.4] 21 | - PHP version: [e.g. 7.4] 22 | 23 | **Additional details** 24 | Add any other details about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Feature request 4 | url: https://github.com/squirephp/squire/discussions/new 5 | about: For ideas or feature requests 6 | - name: Support questions & other 7 | url: https://github.com/squirephp/squire/discussions/new 8 | about: If you have a question or need help installing using the package 9 | -------------------------------------------------------------------------------- /.github/workflows/monorepo-split.yml: -------------------------------------------------------------------------------- 1 | name: monorepo-split 2 | 3 | on: 4 | push: 5 | tags: '*' 6 | 7 | jobs: 8 | provide-packages-list: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: shivammathur/setup-php@v2 13 | with: 14 | php-version: 8.0 15 | coverage: none 16 | - uses: "ramsey/composer-install@v1" 17 | - id: packages-list 18 | run: echo "::set-output name=matrix::$(vendor/bin/monorepo-builder packages-json)" 19 | outputs: 20 | matrix: ${{ steps.packages-list.outputs.matrix }} 21 | 22 | split-monorepo: 23 | needs: provide-packages-list 24 | runs-on: ubuntu-latest 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | package: ${{fromJson(needs.provide-packages-list.outputs.matrix)}} 29 | steps: 30 | - uses: actions/checkout@v2 31 | - id: previous-tag 32 | uses: "WyriHaximus/github-action-get-previous-tag@master" 33 | - name: Monorepo Split of ${{ matrix.package }} 34 | uses: symplify/github-action-monorepo-split@main 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 37 | with: 38 | package_directory: 'packages/${{ matrix.package }}' 39 | repository_organization: 'squirephp' 40 | repository_name: '${{ matrix.package }}' 41 | branch: 3.x 42 | tag: ${{ steps.previous-tag.outputs.tag }} 43 | user_name: "Dan Harrin" 44 | user_email: "dan@danharrin.com" 45 | -------------------------------------------------------------------------------- /.github/workflows/monorepo-validate.yml: -------------------------------------------------------------------------------- 1 | name: monorepo-validate 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | run-validation: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Cache dependencies 13 | uses: actions/cache@v2 14 | with: 15 | path: vendor 16 | key: composer-${{ hashFiles('composer.lock') }} 17 | - name: Setup PHP 18 | uses: shivammathur/setup-php@v2 19 | with: 20 | php-version: 8.1 21 | extensions: mbstring, pdo, pdo_sqlite 22 | coverage: none 23 | - name: Install dependencies 24 | run: composer install -n --prefer-dist 25 | - name: Validate Dependencies are consistent 26 | run: vendor/bin/monorepo-builder validate -------------------------------------------------------------------------------- /.github/workflows/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | name: php-cs-fixer 2 | 3 | on: push 4 | 5 | jobs: 6 | php-cs-fixer: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout code 10 | uses: actions/checkout@v2 11 | with: 12 | ref: ${{ github.head_ref }} 13 | - name: Run PHP CS Fixer 14 | uses: docker://oskarstark/php-cs-fixer-ga 15 | with: 16 | args: --config=.php-cs-fixer.dist.php --allow-risky=yes 17 | - name: Commit changes 18 | uses: stefanzweifel/git-auto-commit-action@v4 19 | with: 20 | commit_message: > 21 | chore: styling 22 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | run-tests: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | php: [8.2, 8.1, 8.0] 14 | laravel: [12.*, 11.*, 10.*, 9.*, 8.*] 15 | dependency-version: [prefer-lowest, prefer-stable] 16 | include: 17 | - laravel: 12.* 18 | testbench: 10.* 19 | - laravel: 11.* 20 | testbench: 9.* 21 | - laravel: 10.* 22 | testbench: 8.* 23 | - laravel: 9.* 24 | testbench: 7.* 25 | - laravel: 8.* 26 | testbench: ^6.23 27 | exclude: 28 | - laravel: 12.* 29 | php: 8.1 30 | - laravel: 12.* 31 | php: 8.0 32 | - laravel: 11.* 33 | php: 8.1 34 | - laravel: 11.* 35 | php: 8.0 36 | - laravel: 10.* 37 | php: 8.0 38 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} 39 | steps: 40 | - uses: actions/checkout@v2 41 | - name: Cache dependencies 42 | uses: actions/cache@v2 43 | with: 44 | path: ~/.composer/cache/files 45 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 46 | - name: Setup PHP 47 | uses: shivammathur/setup-php@v2 48 | with: 49 | php-version: ${{ matrix.php }} 50 | extensions: mbstring, pdo, pdo_sqlite 51 | coverage: none 52 | - name: Install dependencies 53 | run: | 54 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 55 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest 56 | - name: Execute tests 57 | run: vendor/bin/phpunit 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | .phpunit.result.cache 3 | .php-cs-fixer.cache 4 | composer.lock 5 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in([ 5 | __DIR__ . '/packages', 6 | __DIR__ . '/tests', 7 | ]) 8 | ->name('*.php') 9 | ->notName('*.blade.php') 10 | ->ignoreDotFiles(true) 11 | ->ignoreVCS(true); 12 | 13 | return (new PhpCsFixer\Config()) 14 | ->setRules([ 15 | '@PSR12' => true, 16 | 'array_syntax' => ['syntax' => 'short'], 17 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 18 | 'no_unused_imports' => true, 19 | 'not_operator_with_successor_space' => true, 20 | 'trailing_comma_in_multiline' => true, 21 | 'phpdoc_scalar' => true, 22 | 'unary_operator_spaces' => true, 23 | 'binary_operator_spaces' => true, 24 | 'blank_line_before_statement' => [ 25 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 26 | ], 27 | 'phpdoc_single_line_var_spacing' => true, 28 | 'phpdoc_var_without_name' => true, 29 | 'class_attributes_separation' => [ 30 | 'elements' => [ 31 | 'method' => 'one', 32 | ], 33 | ], 34 | 'method_argument_space' => [ 35 | 'on_multiline' => 'ensure_fully_multiline', 36 | 'keep_multiple_spaces_after_comma' => true, 37 | ], 38 | 'single_trait_insert_per_statement' => true, 39 | ]) 40 | ->setFinder($finder); 41 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting Dan Harrin at dan@danharrin.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) Squire 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Package banner 3 |

4 | 5 |

6 | Tests passing 7 | Laravel v8.x 8 | PHP 8 9 |

10 | 11 | Squire is a library of static Eloquent models for fixture data that is commonly needed in web applications, such as countries, currencies and airports. It's based on the concepts of [Caleb Porzio's Sushi package](https://github.com/calebporzio/sushi). 12 | 13 | Common use cases for Squire include: 14 | - Populating dropdown options, such as a country selector on an address form. 15 | - Attaching extra data to other models in your app, such as airport information to a `Flight` model. See the section on [model relationships](#model-relationships). 16 | - [Validating user input.](#validation) 17 | 18 | ## Contents 19 | 20 | - [Installing a Model](#installing-a-model) 21 | - [Using a Model](#using-a-model) 22 | - [Available Models](#available-models) 23 | - [`Squire\Models\Airline`](#squiremodelsairline) 24 | - [`Squire\Models\Airport`](#squiremodelsairport) 25 | - [`Squire\Models\Continent`](#squiremodelscontinent) 26 | - [`Squire\Models\Country`](#squiremodelscountry) 27 | - [`Squire\Models\Currency`](#squiremodelscurrency) 28 | - [Formatting money](#formatting-money) 29 | - [`Squire\Models\GbCounty`](#squiremodelsgbcounty) 30 | - [`Squire\Models\Region`](#squiremodelsregion) 31 | - [`Squire\Models\Timezone`](#squiremodelstimezone) 32 | - [Model Relationships](#model-relationships) 33 | - [Validation](#validation) 34 | - [Creating your own Models](#creating-your-own-models) 35 | - [Adding a localization](#adding-a-localization) 36 | - [Upgrading from 1.x](#upgrading-from-1x) 37 | - [Need Help?](#need-help) 38 | 39 | ## Installing a Model 40 | 41 | You can use Composer to install Squire models into your application. Each model is available in a variety of languages, and you need only install the ones you will use. 42 | 43 | As an example, you can install the `Squire\Models\Country` model in English: 44 | 45 | ``` 46 | composer require squirephp/countries-en 47 | ``` 48 | 49 | **A complete list of [available models](#available-models) is below.** 50 | 51 | ## Using a Model 52 | 53 | You can interact with a Squire model just like you would any other Eloquent model, except that it only handles read-only operations. 54 | 55 | ```php 56 | use Squire\Models\Country; 57 | 58 | Country::all(); // Get information about all countries. 59 | 60 | Country::find('us'); // Get information about the United States. 61 | 62 | Country::where('name', 'like', 'a%')->get(); // Get information about all countries beginning with the letter "a". 63 | ``` 64 | 65 | ## Available Models 66 | 67 | ### `Squire\Models\Airline` 68 | 69 | #### Installation 70 | 71 | | Locale | Installation Command | 72 | |--|--| 73 | | English | `composer require squirephp/airlines-en` | 74 | 75 | #### Schema 76 | 77 | | Column Name | Description | Example | 78 | |--|--|--| 79 | | `alias` | Alternative name of the airline. | `EasyJet Airline` | 80 | | `call_sign` | Call sign of the airline. | `EASY` | 81 | | `code_iata` | [IATA code](https://en.wikipedia.org/wiki/List_of_airline_codes) of the airline. | `u2` | 82 | | `code_icao` | [ICAO code](https://en.wikipedia.org/wiki/List_of_airline_codes) of the airline. |`ezy` | 83 | | `country_id` | [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the airline. | `gb` | 84 | | `name` | Name of the airline. | `easyJet` | 85 | 86 | #### Relationships 87 | 88 | | Relationship name | Model | 89 | |--|--| 90 | | `country` | [`Squire\Models\Country`](#squiremodelscountry) | 91 | | `continent` | [`Squire\Models\Continent`](#squiremodelscontinent) | 92 | 93 | 94 | ### `Squire\Models\Airport` 95 | 96 | #### Installation 97 | 98 | | Locale | Installation Command | 99 | |--|--| 100 | | English | `composer require squirephp/airports-en` | 101 | 102 | #### Schema 103 | 104 | | Column Name | Description | Example | 105 | |--|--|--| 106 | | `code_iata` | [IATA code](https://en.wikipedia.org/wiki/IATA_airport_code) of the airport. | `lhr` | 107 | | `code_icao` | [ICAO code](https://en.wikipedia.org/wiki/ICAO_airport_code) of the airport. |`egll` | 108 | | `country_id` | [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the airport. | `gb` | 109 | | `municipality` | Municipality of the airport. | `London` | 110 | | `name` | Name of the airport. | `London Heathrow Airport` | 111 | | `timezone_id` | [PHP timezone identifier](https://www.php.net/manual/en/timezones.php) of the airport. | `Europe/London` | 112 | 113 | #### Relationships 114 | 115 | | Relationship name | Model | 116 | |--|--| 117 | | `country` | [`Squire\Models\Country`](#squiremodelscountry) | 118 | | `timezone` | [`Squire\Models\Timezone`](#squiremodelstimezone) | 119 | 120 | ### `Squire\Models\Continent` 121 | 122 | #### Installation 123 | 124 | | Locale | Installation Command | 125 | | ------- | -------------------------------------------------- | 126 | | German | `composer require squirephp/continents-de` | 127 | | English | `composer require squirephp/continents-en` | 128 | | Polish | `composer require squirephp/continents-pl` | 129 | | Italian | `composer require squirephp-italian/continents-it` | 130 | 131 | #### Schema 132 | 133 | | Column Name | Description | Example | 134 | |--|--|--| 135 | | `code` | Two letter continent code. | `na` | 136 | | `name` | Continent name. | `North America` | 137 | 138 | #### Relationships 139 | 140 | | Relationship name | Model | 141 | |--|--| 142 | | `countries` | [`Squire\Models\Country`](#squiremodelscountry) | 143 | | `regions` | [`Squire\Models\Region`](#squiremodelsregion) | 144 | | `timezones` | [`Squire\Models\Timezone`](#squiremodelstimezone) | 145 | 146 | ### `Squire\Models\Country` 147 | 148 | #### Installation 149 | 150 | | Locale | Installation Command | 151 | | ------- | ------------------------------------------------------- | 152 | | English | `composer require squirephp/countries-en` | 153 | | French | `composer require squirephp/countries-fr` | 154 | | German | `composer require squirephp/countries-de` | 155 | | Polish | `composer require squirephp/countries-pl` | 156 | | Spanish | `composer require squirephp/countries-es` | 157 | | Dutch | `composer require quickstreambe/squirephp-countries-nl` | 158 | | Italian | `composer require squirephp-italian/countries-it` | 159 | 160 | #### Schema 161 | 162 | | Column Name | Description | Example | 163 | |--|--|--| 164 | | `calling_code` | [E.164](https://en.wikipedia.org/wiki/E.164) country calling code. | `1` | 165 | | `capital_city` | Capital city of the country. | `Washington` | 166 | | `code_2` | [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). | `us` | 167 | | `code_3` | [ISO 3166-1 alpha-3 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3). | `usa` | 168 | | `continent_id` | Two letter continent code of the country. | `na` | 169 | | `currency_id` | [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) alphabetic currency code of the country. | `usd` | 170 | | `flag` | Unicode flag of the country. | `🇺🇸` | 171 | | `name` | Country name. | `United States` | 172 | 173 | #### Relationships 174 | 175 | | Relationship name | Model | 176 | |--|--| 177 | | `airlines` | [`Squire\Models\Airline`](#squiremodelsairline) | 178 | | `airports` | [`Squire\Models\Airport`](#squiremodelsairport) | 179 | | `continent` | [`Squire\Models\Continent`](#squiremodelscontinent) | 180 | | `currency` | [`Squire\Models\Currency`](#squiremodelscurrency) | 181 | | `regions` | [`Squire\Models\Region`](#squiremodelsregion) | 182 | | `timezones` | [`Squire\Models\Timezone`](#squiremodelstimezone) | 183 | 184 | ### `Squire\Models\Currency` 185 | 186 | #### Installation 187 | 188 | | Locale | Installation Command | 189 | |--|--| 190 | | English | `composer require squirephp/currencies-en` | 191 | 192 | #### Schema 193 | 194 | | Column Name | Description | Example | 195 | |--|--|--| 196 | | `code_alphabetic` | [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) alphabetic currency code. | `usd` | 197 | | `code_numeric` | [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) numeric currency code. | `840` | 198 | | `decimal_digits` | Number of decimal digits to use when formatting this currency. | `2` | 199 | | `name` | Currency name. | `US Dollar` | 200 | | `name_plural` | Plural currency name. | `US Dollars` | 201 | | `rounding` | The formatting precison of this currency. | `0` | 202 | | `symbol` | International currency symbol. | `$` | 203 | | `symbol_native` | Native currency symbol. | `$` | 204 | 205 | #### Relationships 206 | 207 | | Relationship name | Model | 208 | |--|--| 209 | | `countries` | [`Squire\Models\Country`](#squiremodelscountry) | 210 | 211 | #### Formatting money 212 | 213 | You may use the `format()` method on any currency model instance to format a given number in that currency: 214 | 215 | ```php 216 | Currency::find('usd')->format(500) // $5.00 217 | Currency::find('usd')->format(500, true) // $500.00, converted 218 | ``` 219 | 220 | This functionality uses [`akaunting/laravel-money`](https://github.com/akaunting/laravel-money) internally. 221 | 222 | ### `Squire\Models\GbCounty` 223 | 224 | #### Installation 225 | 226 | | Locale | Installation Command | 227 | |--|--| 228 | | English | `composer require squirephp/gb-counties-en` | 229 | 230 | #### Schema 231 | 232 | | Column Name | Description | Example | 233 | |--|--|--| 234 | | `code` | [ISO 3166-2 county code](https://en.wikipedia.org/wiki/ISO_3166-2). | `gb-ess` | 235 | | `name` | County name. | `Essex` | 236 | | `region_id` | [ISO 3166-2 region code](https://en.wikipedia.org/wiki/ISO_3166-2) of the county. | `gb-eng` | 237 | 238 | #### Relationships 239 | 240 | | Relationship name | Model | 241 | |--|--| 242 | | `region` | [`Squire\Models\Region`](#squiremodelsregion) | 243 | 244 | ### `Squire\Models\Region` 245 | 246 | #### Installation 247 | 248 | | Locale | Installation Command | 249 | |--|--| 250 | | English | `composer require squirephp/regions-en` | 251 | 252 | #### Schema 253 | 254 | | Column Name | Description | Example | 255 | |--|--|--| 256 | | `code` | [ISO 3166-2 region code](https://en.wikipedia.org/wiki/ISO_3166-2). | `us-ny` | 257 | | `country_id` | [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). | `us` | 258 | | `name` | Region name. | `New York` | 259 | 260 | #### Relationships 261 | 262 | | Relationship name | Model | 263 | |--|--| 264 | | `continent` | [`Squire\Models\Continent`](#squiremodelscontinent) | 265 | | `country` | [`Squire\Models\Country`](#squiremodelscountry) | 266 | | `gbCounties` | [`Squire\Models\GbCounty`](#squiremodelsgbcounty) | 267 | 268 | ### `Squire\Models\Timezone` 269 | 270 | #### Installation 271 | 272 | | Locale | Installation Command | 273 | |--|--| 274 | | English | `composer require squirephp/timezones-en` | 275 | 276 | #### Schema 277 | 278 | | Column Name | Description | Example | 279 | |--|--|--| 280 | | `code` | [PHP timezone identifier](https://www.php.net/manual/en/timezones.php). | `America/New_York` | 281 | | `country_id` | [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). | `us` | 282 | | `long_name` | Full timezone name. | `America/New York` | 283 | | `name` | Short timezone name. | `New York` | 284 | 285 | #### Relationships 286 | 287 | | Relationship name | Model | 288 | |--|--| 289 | | `airports` | [`Squire\Models\Airport`](#squiremodelsairport) | 290 | | `continent` | [`Squire\Models\Continent`](#squiremodelscontinent) | 291 | | `country` | [`Squire\Models\Country`](#squiremodelscountry) | 292 | 293 | #### Methods 294 | 295 | | Method name | Description | 296 | |--|--| 297 | | `getOffset($dateTime)` | Returns the timezone offset from GMT. | 298 | 299 | ## Model Relationships 300 | 301 | Implementing an Eloquent relationship between a model in your app and a Squire model is very simple. There are a couple of approaches you could take. 302 | 303 | ### Using Inheritance 304 | 305 | The simplest option is to create a new model in your app, and let it extend the Squire model. Your new app model will now behave like the original Squire model, except you can register new methods and customise it to your liking: 306 | 307 | ```php 308 | hasMany(User::class); 320 | } 321 | } 322 | ``` 323 | 324 | ### Using `resolveRelationUsing()` 325 | 326 | Another option is the `resolveRelationUsing()` method. This allows you to dynamically register a relationship for a Squire model from anywhere in your app, for example, within a service provider: 327 | 328 | ```php 329 | use App\Models\User; 330 | use Illuminate\Database\Eloquent\Relations\HasMany; 331 | use Squire\Models\Country; 332 | 333 | Country::resolveRelationUsing('users', function (Country $country): HasMany { 334 | return $country->hasMany(User::class); 335 | }); 336 | ``` 337 | 338 | ## Validation 339 | 340 | Squire includes a validation rule for each model installed in your app. These allow you to easily validate user input to ensure that it matches a record in a specific model. 341 | 342 | Rules can be found in the `Squire\Rules` namespace. To use one, simply construct a new rule class and pass in the model column name that you would like to validate against: 343 | 344 | ```php 345 | use Squire\Rules; 346 | 347 | $request->validate([ 348 | 'country' => ['required', 'string', new Rules\CountryRule('name')], 349 | ]); 350 | ``` 351 | 352 | This code will validate the `country` input against the `name` column on the [`Squire\Models\Country` model](#squiremodelscountry). If the user enters a country that does not exist, a validation error will be thrown. 353 | 354 | ## Creating your own Models 355 | 356 | Squire may not always have a model available for the information you require. In this case, you may want to create your own. 357 | 358 | ### Creating a Model 359 | 360 | Squire models are very simple classes that extend `Squire\Model`. Install it with: 361 | 362 | ``` 363 | composer require squirephp/model 364 | ``` 365 | 366 | Your model class should contain a single static property, `$schema`. This contains the column structure for your model, and should match the format of the source data. 367 | 368 | ```php 369 | 'string', 379 | 'name' => 'string', 380 | ]; 381 | } 382 | ``` 383 | 384 | ### Attaching a Model Source 385 | 386 | Your model will require at least one data source to be registered. Each registered data source is associated with a locale. To register a data source, you will need to interact with `Squire\Repository`. Install it with: 387 | 388 | ``` 389 | composer require squirephp/repository 390 | ``` 391 | 392 | Inside a service provider, register an English source for your model: 393 | 394 | ```php 395 | validate([ 490 | 'country' => ['required', 'string', new CountryRule('name')], 491 | ]); 492 | ``` 493 | 494 | 3.x: 495 | 496 | ```php 497 | use Squire\Models\Country; 498 | use Squire\Rules\CountryRule; 499 | 500 | Country::find('us'); 501 | 502 | $request->validate([ 503 | 'country' => ['required', 'string', new CountryRule('name')], 504 | ]); 505 | ``` 506 | 507 | All properties and methods in [custom models](#creating-a-model) and [custom validation rules](#creating-a-validation-rule) now need to have the correct types. These can be found in the relevant section of the documentation. 508 | 509 | ### Breaking Changes Introduced in 3.x 510 | 511 | - The minimum PHP version has been bumped to v8.0, and the minimum Laravel version to v8.x. 512 | - Validation rules have been renamed, so they all end with `Rule`. This allows both the model and rule to be imported into the same class without the use of aliasing. 513 | - Types have been introduced to all classes. If you have created [custom models](#creating-a-model) and [custom validation rules](#creating-a-validation-rule), properties and methods now need to use the correct types. 514 | - The primary key of airports is now their ICAO code. The region relationship has been removed and replaced with country. The local code has been removed. 515 | - Empty string values are now null. 516 | 517 | ## Need Help? 518 | 519 | 🐞 If you spot a bug with this package, please [submit a detailed issue](https://github.com/squirephp/squire/issues/new), and wait for assistance. 520 | 521 | 🤔 If you have a question or feature request, please [start a new discussion](https://github.com/squirephp/squire/discussions/new). 522 | 523 | 🔐 If you discover a vulnerability within the package, please review our [security policy](https://github.com/squirephp/squire/blob/main/SECURITY.md). 524 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 3.x | :white_check_mark: | 8 | | 2.x | :white_check_mark: | 9 | | 1.x | :white_check_mark: | 10 | 11 | ## Reporting a Vulnerability 12 | 13 | If you discover a security vulnerability within Squire, please email Dan Harrin via [dan@danharrin.com](mailto:dan@danharrin.com). All security vulnerabilities will be promptly addressed. 14 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squirephp/squire", 3 | "authors": [ 4 | { 5 | "name": "Dan Harrin", 6 | "email": "dan@danharrin.com" 7 | }, 8 | { 9 | "name": "Krzysztof Rewak", 10 | "email": "krzysztof.rewak@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "akaunting/laravel-money": "^1.2|^2.1|^3.0|^4.0|^5.1|^6.0", 15 | "ext-pdo_sqlite": "*", 16 | "illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0", 17 | "illuminate/database": "^8.40|^9.0|^10.0|^11.0|^12.0", 18 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0", 19 | "php": "^8.0" 20 | }, 21 | "require-dev": { 22 | "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0", 23 | "phpunit/phpunit": "^9.4|^10.0|^11.0", 24 | "symplify/monorepo-builder": "^9.4.21" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Squire\\": [ 29 | "packages/airlines-en/src", 30 | "packages/airlines/src", 31 | "packages/airports-en/src", 32 | "packages/airports/src", 33 | "packages/continents-de/src", 34 | "packages/continents-en/src", 35 | "packages/continents-pl/src", 36 | "packages/continents/src", 37 | "packages/countries-de/src", 38 | "packages/countries-en/src", 39 | "packages/countries-es/src", 40 | "packages/countries-fr/src", 41 | "packages/countries-pl/src", 42 | "packages/countries/src", 43 | "packages/currencies-en/src", 44 | "packages/currencies/src", 45 | "packages/gb-counties-en/src", 46 | "packages/gb-counties/src", 47 | "packages/model/src", 48 | "packages/regions-en/src", 49 | "packages/regions/src", 50 | "packages/repository/src", 51 | "packages/rule/src", 52 | "packages/timezones-en/src", 53 | "packages/timezones/src" 54 | ] 55 | } 56 | }, 57 | "autoload-dev": { 58 | "psr-4": { 59 | "Squire\\Tests\\": "tests" 60 | } 61 | }, 62 | "extra": { 63 | "laravel": { 64 | "providers": [ 65 | "Squire\\GbCountiesServiceProvider", 66 | "Squire\\ContinentsEnServiceProvider", 67 | "Squire\\AirportsServiceProvider", 68 | "Squire\\CountriesDeServiceProvider", 69 | "Squire\\AirlinesServiceProvider", 70 | "Squire\\CountriesServiceProvider", 71 | "Squire\\RegionsEnServiceProvider", 72 | "Squire\\ModelServiceProvider", 73 | "Squire\\GbCountiesEnServiceProvider", 74 | "Squire\\AirlinesEnServiceProvider", 75 | "Squire\\CountriesEnServiceProvider", 76 | "Squire\\ContinentsDeServiceProvider", 77 | "Squire\\CountriesFrServiceProvider", 78 | "Squire\\CountriesEsServiceProvider", 79 | "Squire\\TimezonesEnServiceProvider", 80 | "Squire\\CountriesPlServiceProvider", 81 | "Squire\\TimezonesServiceProvider", 82 | "Squire\\ContinentsServiceProvider", 83 | "Squire\\AirportsEnServiceProvider", 84 | "Squire\\CurrenciesEnServiceProvider", 85 | "Squire\\ContinentsPlServiceProvider", 86 | "Squire\\CurrenciesServiceProvider", 87 | "Squire\\RegionsServiceProvider", 88 | "Squire\\RepositoryServiceProvider" 89 | ], 90 | "aliases": { 91 | "RepositoryManager": "Squire\\Repository\\Facades\\Repository" 92 | } 93 | } 94 | }, 95 | "replace": { 96 | "squirephp/airlines": "self.version", 97 | "squirephp/airlines-en": "self.version", 98 | "squirephp/airports": "self.version", 99 | "squirephp/airports-en": "self.version", 100 | "squirephp/continents": "self.version", 101 | "squirephp/continents-de": "self.version", 102 | "squirephp/continents-en": "self.version", 103 | "squirephp/continents-pl": "self.version", 104 | "squirephp/countries": "self.version", 105 | "squirephp/countries-de": "self.version", 106 | "squirephp/countries-en": "self.version", 107 | "squirephp/countries-es": "self.version", 108 | "squirephp/countries-fr": "self.version", 109 | "squirephp/countries-pl": "self.version", 110 | "squirephp/currencies": "self.version", 111 | "squirephp/currencies-en": "self.version", 112 | "squirephp/gb-counties": "self.version", 113 | "squirephp/gb-counties-en": "self.version", 114 | "squirephp/model": "self.version", 115 | "squirephp/regions": "self.version", 116 | "squirephp/regions-en": "self.version", 117 | "squirephp/repository": "self.version", 118 | "squirephp/rule": "self.version", 119 | "squirephp/timezones": "self.version", 120 | "squirephp/timezones-en": "self.version" 121 | }, 122 | "minimum-stability": "dev", 123 | "prefer-stable": true 124 | } 125 | -------------------------------------------------------------------------------- /monorepo-builder.php: -------------------------------------------------------------------------------- 1 | parameters(); 15 | 16 | $parameters->set(Option::DATA_TO_APPEND, [ 17 | 'autoload-dev' => [ 18 | 'psr-4' => [ 19 | 'Squire\Tests\\' => 'tests', 20 | ], 21 | ], 22 | 'require-dev' => [ 23 | 'orchestra/testbench' => '^6.23|^7.0|^8.0|^9.0|^10.0', 24 | 'phpunit/phpunit' => '^9.4|^10.0|^11.0', 25 | 'symplify/monorepo-builder' => '^9.4.21', 26 | ], 27 | 'minimum-stability' => 'dev', 28 | 'prefer-stable' => true 29 | ]); 30 | 31 | $parameters->set(Option::DATA_TO_REMOVE, [ 32 | 'minimum-stability' => '*', 33 | ]); 34 | 35 | $services = $containerConfigurator->services(); 36 | 37 | # Release workers - in order to execute 38 | $services->set(UpdateReplaceReleaseWorker::class); 39 | $services->set(SetCurrentMutualDependenciesReleaseWorker::class); 40 | $services->set(TagVersionReleaseWorker::class); 41 | $services->set(PushTagReleaseWorker::class); 42 | $services->set(SetNextMutualDependenciesReleaseWorker::class); 43 | $services->set(UpdateBranchAliasReleaseWorker::class); 44 | $services->set(PushNextDevReleaseWorker::class); 45 | }; -------------------------------------------------------------------------------- /packages/airlines-en/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squirephp/airlines-en", 3 | "description": "A library containing the English translation of Squire's Airline model.", 4 | "keywords": [ 5 | "squire" 6 | ], 7 | "license": "MIT", 8 | "homepage": "https://github.com/squirephp", 9 | "support": { 10 | "issues": "https://github.com/squirephp/squire/issues", 11 | "source": "https://github.com/squirephp/squire" 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Dan Harrin", 16 | "email": "dan@danharrin.com" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.0", 21 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0", 22 | "squirephp/airlines": "self.version", 23 | "squirephp/repository": "self.version" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Squire\\": "src" 28 | } 29 | }, 30 | "extra": { 31 | "laravel": { 32 | "providers": [ 33 | "Squire\\AirlinesEnServiceProvider" 34 | ] 35 | } 36 | }, 37 | "config": { 38 | "sort-packages": true 39 | }, 40 | "minimum-stability": "dev" 41 | } 42 | -------------------------------------------------------------------------------- /packages/airlines-en/src/AirlinesEnServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid airline.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/airlines/src/AirlinesServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-airlines'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-airlines'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/airlines/src/Models/Airline.php: -------------------------------------------------------------------------------- 1 | 'string', 13 | 'alias' => 'string', 14 | 'call_sign' => 'string', 15 | 'code_iata' => 'string', 16 | 'code_icao' => 'string', 17 | 'country_id' => 'string', 18 | 'name' => 'string', 19 | ]; 20 | 21 | public function country(): BelongsTo 22 | { 23 | return $this->belongsTo(Country::class); 24 | } 25 | 26 | public function continent(): HasOneThrough 27 | { 28 | return $this->hasOneThrough(Continent::class, Country::class); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/airlines/src/Rules/AirlineRule.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid airport.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/airports/src/AirportsServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-airports'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-airports'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/airports/src/Models/Airport.php: -------------------------------------------------------------------------------- 1 | 'string', 12 | 'code_iata' => 'string', 13 | 'code_icao' => 'string', 14 | 'country_id' => 'string', 15 | 'municipality' => 'string', 16 | 'name' => 'string', 17 | 'timezone_id' => 'string', 18 | ]; 19 | 20 | public function country(): BelongsTo 21 | { 22 | return $this->belongsTo(Country::class); 23 | } 24 | 25 | public function timezone(): BelongsTo 26 | { 27 | return $this->belongsTo(Timezone::class); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/airports/src/Rules/AirportRule.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid continent.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/continents/src/ContinentsServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-continents'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-continents'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/continents/src/Models/Continent.php: -------------------------------------------------------------------------------- 1 | 'string', 13 | 'code' => 'string', 14 | 'name' => 'string', 15 | ]; 16 | 17 | public function countries(): HasMany 18 | { 19 | return $this->hasMany(Country::class); 20 | } 21 | 22 | public function regions(): HasManyThrough 23 | { 24 | return $this->hasManyThrough(Region::class, Country::class); 25 | } 26 | 27 | public function timezones(): HasManyThrough 28 | { 29 | return $this->hasManyThrough(Timezone::class, Country::class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/continents/src/Rules/ContinentRule.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid country.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/countries/src/CountriesServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-countries'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-countries'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/countries/src/Models/Country.php: -------------------------------------------------------------------------------- 1 | 'string', 13 | 'calling_code' => 'string', 14 | 'capital_city' => 'string', 15 | 'code_2' => 'string', 16 | 'code_3' => 'string', 17 | 'continent_id' => 'string', 18 | 'currency_id' => 'string', 19 | 'flag' => 'string', 20 | 'name' => 'string', 21 | ]; 22 | 23 | public function airlines(): HasMany 24 | { 25 | return $this->hasMany(Airline::class); 26 | } 27 | 28 | public function airports(): HasMany 29 | { 30 | return $this->hasMany(Airport::class); 31 | } 32 | 33 | public function continent(): BelongsTo 34 | { 35 | return $this->belongsTo(Continent::class); 36 | } 37 | 38 | public function currency(): BelongsTo 39 | { 40 | return $this->belongsTo(Currency::class); 41 | } 42 | 43 | public function regions(): HasMany 44 | { 45 | return $this->hasMany(Region::class); 46 | } 47 | 48 | public function timezones(): HasMany 49 | { 50 | return $this->hasMany(Timezone::class); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/countries/src/Rules/CountryRule.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid currency.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/currencies/src/CurrenciesServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-currencies'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-currencies'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/currencies/src/Models/Currency.php: -------------------------------------------------------------------------------- 1 | 'string', 13 | 'code_alphabetic' => 'string', 14 | 'code_numeric' => 'integer', 15 | 'decimal_digits' => 'integer', 16 | 'name' => 'string', 17 | 'name_plural' => 'string', 18 | 'rounding' => 'integer', 19 | 'symbol' => 'string', 20 | 'symbol_native' => 'string', 21 | ]; 22 | 23 | public function countries(): HasMany 24 | { 25 | return $this->hasMany(Country::class); 26 | } 27 | 28 | public function format(float $number, bool $shouldConvert = false): string 29 | { 30 | return (new Money\Money( 31 | $number, 32 | (new Money\Currency(strtoupper($this->id))), 33 | $shouldConvert 34 | ))->format(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/currencies/src/Rules/CurrencyRule.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid county.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/gb-counties/src/GbCountiesServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-gb-counties'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-gb-counties'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/gb-counties/src/Models/GbCounty.php: -------------------------------------------------------------------------------- 1 | 'string', 12 | 'code' => 'string', 13 | 'name' => 'string', 14 | 'region_id' => 'string', 15 | ]; 16 | 17 | public function region(): BelongsTo 18 | { 19 | return $this->belongsTo(Region::class); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/gb-counties/src/Rules/GbCountyRule.php: -------------------------------------------------------------------------------- 1 | storage_path('framework/cache'), 6 | 7 | 'cache-prefix' => 'squire', 8 | 9 | ]; 10 | -------------------------------------------------------------------------------- /packages/model/src/Model.php: -------------------------------------------------------------------------------- 1 | getFileName()); 80 | } 81 | 82 | protected static function getSourceUpdatedAt(?string $locale = null): int 83 | { 84 | return filemtime(Repository::getSource(static::class, $locale)); 85 | } 86 | 87 | protected static function setSqliteConnection(string $database): void 88 | { 89 | static::$sqliteConnections[static::class] = app(ConnectionFactory::class)->make([ 90 | 'driver' => 'sqlite', 91 | 'database' => $database, 92 | ]); 93 | } 94 | 95 | protected static function isCacheable(): bool 96 | { 97 | $cacheDirectory = static::getCacheDirectory(); 98 | 99 | return file_exists($cacheDirectory) && is_writable($cacheDirectory); 100 | } 101 | 102 | public static function cache(array $locales = []) 103 | { 104 | if (! count($locales)) { 105 | $locales = array_keys(Repository::getSources(static::class)); 106 | } 107 | 108 | collect($locales) 109 | ->filter(fn (string $locale): bool => Repository::sourceIsRegistered(static::class, $locale)) 110 | ->each(function (string $locale): void { 111 | $cachePath = static::getCachePath($locale); 112 | 113 | file_put_contents($cachePath, ''); 114 | 115 | static::setSqliteConnection($cachePath); 116 | 117 | static::migrate($locale); 118 | 119 | $modelUpdatedAt = static::getModelUpdatedAt(); 120 | $sourceUpdatedAt = static::getSourceUpdatedAt($locale); 121 | 122 | touch($cachePath, $modelUpdatedAt >= $sourceUpdatedAt ? $modelUpdatedAt : $sourceUpdatedAt); 123 | }); 124 | } 125 | 126 | public static function migrate(?string $locale = null): void 127 | { 128 | $tableName = (new static())->getTable(); 129 | 130 | static::resolveConnection()->getSchemaBuilder()->create($tableName, function (Blueprint $table): void { 131 | foreach (static::$schema as $name => $type) { 132 | $table->{$type}($name)->nullable(); 133 | } 134 | }); 135 | 136 | $data = collect(Repository::fetchData(static::class)); 137 | 138 | $schema = collect(str_getcsv($data->first())); 139 | 140 | $data->transform(function (string $line) use ($schema): Collection { 141 | return $schema->combine( 142 | array_map(fn ($value) => $value !== '' ? $value : null, str_getcsv($line)) 143 | ); 144 | }); 145 | 146 | $data->shift(); 147 | 148 | foreach (array_chunk($data->toArray(), 100) ?? [] as $dataToInsert) { 149 | if (empty($dataToInsert)) { 150 | continue; 151 | } 152 | 153 | static::insert($dataToInsert); 154 | } 155 | } 156 | 157 | public static function resolveConnection($connection = null): SQLiteConnection 158 | { 159 | return static::$sqliteConnections[static::class]; 160 | } 161 | 162 | public function usesTimestamps(): bool 163 | { 164 | return false; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /packages/model/src/ModelServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 12 | __DIR__ . '/../config/squire.php' => config_path('squire.php'), 13 | ]); 14 | 15 | $this->mergeConfigFrom( 16 | __DIR__ . '/../config/squire.php', 17 | 'squire' 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/regions-en/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squirephp/regions-en", 3 | "description": "A library containing the English translation of Squire's Region model.", 4 | "keywords": [ 5 | "squire" 6 | ], 7 | "license": "MIT", 8 | "homepage": "https://github.com/squirephp", 9 | "support": { 10 | "issues": "https://github.com/squirephp/squire/issues", 11 | "source": "https://github.com/squirephp/squire" 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Dan Harrin", 16 | "email": "dan@danharrin.com" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.0", 21 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0", 22 | "squirephp/regions": "self.version", 23 | "squirephp/repository": "self.version" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Squire\\": "src" 28 | } 29 | }, 30 | "extra": { 31 | "laravel": { 32 | "providers": [ 33 | "Squire\\RegionsEnServiceProvider" 34 | ] 35 | } 36 | }, 37 | "config": { 38 | "sort-packages": true 39 | }, 40 | "minimum-stability": "dev" 41 | } 42 | -------------------------------------------------------------------------------- /packages/regions-en/src/RegionsEnServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid region.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/regions/src/Models/Region.php: -------------------------------------------------------------------------------- 1 | 'string', 14 | 'code' => 'string', 15 | 'country_id' => 'string', 16 | 'name' => 'string', 17 | ]; 18 | 19 | public function continent(): HasOneThrough 20 | { 21 | return $this->hasOneThrough(Continent::class, Country::class); 22 | } 23 | 24 | public function country(): BelongsTo 25 | { 26 | return $this->belongsTo(Country::class); 27 | } 28 | 29 | public function gbCounties(): HasMany 30 | { 31 | return $this->hasMany(GbCounty::class); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/regions/src/RegionsServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-regions'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-regions'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/regions/src/Rules/RegionRule.php: -------------------------------------------------------------------------------- 1 | getSource($name, $locale); 16 | 17 | return $this->fetchDataFromSource($source); 18 | } 19 | 20 | public function getSource(string $name, ?string $locale = null): string 21 | { 22 | if ($locale && ! $this->sourceIsRegistered($name, $locale)) { 23 | throw new TranslationNotFoundException($name, $locale); 24 | } 25 | 26 | if (! $locale) { 27 | $locale = $this->getLocale($name); 28 | } 29 | 30 | return $this->getSources($name)[$locale]; 31 | } 32 | 33 | public function sourceIsRegistered(string $name, ?string $locale = null): bool 34 | { 35 | if (! $locale) { 36 | return array_key_exists($name, $this->sources); 37 | } 38 | 39 | return array_key_exists($name, $this->sources) && array_key_exists($locale, $this->sources[$name]); 40 | } 41 | 42 | public function getLocale(string $name): string 43 | { 44 | if ($this->sourceIsRegistered($name, $appLocale = App::getLocale())) { 45 | return $appLocale; 46 | } 47 | 48 | if ($this->sourceIsRegistered($name, $appFallbackLocale = config('app.fallback_locale'))) { 49 | return $appFallbackLocale; 50 | } 51 | 52 | return array_key_first($this->getSources($name)); 53 | } 54 | 55 | public function getSources(?string $name = null): array | string 56 | { 57 | if (! $name) { 58 | return $this->sources; 59 | } 60 | 61 | if (! $this->sourceIsRegistered($name) || ! count($this->sources[$name])) { 62 | throw new SourceNotFoundException($name); 63 | } 64 | 65 | return $this->sources[$name]; 66 | } 67 | 68 | public function fetchDataFromSource($source): array 69 | { 70 | return file($source); 71 | } 72 | 73 | public function registerSource(string $name, string $locale, string $path): void 74 | { 75 | if (! $this->sourceIsRegistered($name)) { 76 | $this->sources[$name] = []; 77 | } 78 | 79 | $this->sources[$name][$locale] = realpath($path); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /packages/repository/src/RepositoryServiceProvider.php: -------------------------------------------------------------------------------- 1 | RepositoryManager::class, 11 | ]; 12 | } 13 | -------------------------------------------------------------------------------- /packages/rule/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squirephp/rule", 3 | "description": "A library containing the base Squire rule class.", 4 | "keywords": [ 5 | "squire" 6 | ], 7 | "license": "MIT", 8 | "homepage": "https://github.com/squirephp", 9 | "support": { 10 | "issues": "https://github.com/squirephp/squire/issues", 11 | "source": "https://github.com/squirephp/squire" 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Dan Harrin", 16 | "email": "dan@danharrin.com" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.0", 21 | "illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0", 22 | "illuminate/database": "^8.40|^9.0|^10.0|^11.0|^12.0", 23 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Squire\\": "src" 28 | } 29 | }, 30 | "config": { 31 | "sort-packages": true 32 | }, 33 | "minimum-stability": "dev" 34 | } 35 | -------------------------------------------------------------------------------- /packages/rule/src/Rule.php: -------------------------------------------------------------------------------- 1 | column = $column; 18 | } 19 | } 20 | 21 | public function message(): string 22 | { 23 | return __($this->message); 24 | } 25 | 26 | public function passes($attribute, $value): bool 27 | { 28 | return $this->getQueryBuilder()->where($this->column, $value)->exists(); 29 | } 30 | 31 | abstract protected function getQueryBuilder(): Builder; 32 | } 33 | -------------------------------------------------------------------------------- /packages/timezones-en/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squirephp/timezones-en", 3 | "description": "A library containing the English translation of Squire's Timezone model.", 4 | "keywords": [ 5 | "squire" 6 | ], 7 | "license": "MIT", 8 | "homepage": "https://github.com/squirephp", 9 | "support": { 10 | "issues": "https://github.com/squirephp/squire/issues", 11 | "source": "https://github.com/squirephp/squire" 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Dan Harrin", 16 | "email": "dan@danharrin.com" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.0", 21 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0", 22 | "squirephp/repository": "self.version", 23 | "squirephp/timezones": "self.version" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Squire\\": "src" 28 | } 29 | }, 30 | "extra": { 31 | "laravel": { 32 | "providers": [ 33 | "Squire\\TimezonesEnServiceProvider" 34 | ] 35 | } 36 | }, 37 | "config": { 38 | "sort-packages": true 39 | }, 40 | "minimum-stability": "dev" 41 | } 42 | -------------------------------------------------------------------------------- /packages/timezones-en/resources/data.csv: -------------------------------------------------------------------------------- 1 | id,code,country_id,long_name,name 2 | Africa/Abidjan,Africa/Abidjan,ci,Africa/Abidjan,Abidjan 3 | Africa/Accra,Africa/Accra,gh,Africa/Accra,Accra 4 | Africa/Addis_Ababa,Africa/Addis_Ababa,et,Africa/Addis Ababa,Addis Ababa 5 | Africa/Algiers,Africa/Algiers,dz,Africa/Algiers,Algiers 6 | Africa/Asmara,Africa/Asmara,er,Africa/Asmara,Asmara 7 | Africa/Bamako,Africa/Bamako,ml,Africa/Bamako,Bamako 8 | Africa/Bangui,Africa/Bangui,cf,Africa/Bangui,Bangui 9 | Africa/Banjul,Africa/Banjul,gm,Africa/Banjul,Banjul 10 | Africa/Bissau,Africa/Bissau,gw,Africa/Bissau,Bissau 11 | Africa/Blantyre,Africa/Blantyre,mw,Africa/Blantyre,Blantyre 12 | Africa/Brazzaville,Africa/Brazzaville,cg,Africa/Brazzaville,Brazzaville 13 | Africa/Bujumbura,Africa/Bujumbura,bi,Africa/Bujumbura,Bujumbura 14 | Africa/Cairo,Africa/Cairo,eg,Africa/Cairo,Cairo 15 | Africa/Casablanca,Africa/Casablanca,ma,Africa/Casablanca,Casablanca 16 | Africa/Ceuta,Africa/Ceuta,es,Africa/Ceuta,Ceuta 17 | Africa/Conakry,Africa/Conakry,gn,Africa/Conakry,Conakry 18 | Africa/Dakar,Africa/Dakar,sn,Africa/Dakar,Dakar 19 | Africa/Dar_es_Salaam,Africa/Dar_es_Salaam,tz,Africa/Dar es Salaam,Dar es Salaam 20 | Africa/Djibouti,Africa/Djibouti,dj,Africa/Djibouti,Djibouti 21 | Africa/Douala,Africa/Douala,cm,Africa/Douala,Douala 22 | Africa/El_Aaiun,Africa/El_Aaiun,eh,Africa/El Aaiun,El Aaiun 23 | Africa/Freetown,Africa/Freetown,sl,Africa/Freetown,Freetown 24 | Africa/Gaborone,Africa/Gaborone,bw,Africa/Gaborone,Gaborone 25 | Africa/Harare,Africa/Harare,zw,Africa/Harare,Harare 26 | Africa/Johannesburg,Africa/Johannesburg,za,Africa/Johannesburg,Johannesburg 27 | Africa/Juba,Africa/Juba,ss,Africa/Juba,Juba 28 | Africa/Kampala,Africa/Kampala,ug,Africa/Kampala,Kampala 29 | Africa/Khartoum,Africa/Khartoum,sd,Africa/Khartoum,Khartoum 30 | Africa/Kigali,Africa/Kigali,rw,Africa/Kigali,Kigali 31 | Africa/Kinshasa,Africa/Kinshasa,cd,Africa/Kinshasa,Kinshasa 32 | Africa/Lagos,Africa/Lagos,ng,Africa/Lagos,Lagos 33 | Africa/Libreville,Africa/Libreville,ga,Africa/Libreville,Libreville 34 | Africa/Lome,Africa/Lome,tg,Africa/Lome,Lome 35 | Africa/Luanda,Africa/Luanda,ao,Africa/Luanda,Luanda 36 | Africa/Lubumbashi,Africa/Lubumbashi,cd,Africa/Lubumbashi,Lubumbashi 37 | Africa/Lusaka,Africa/Lusaka,zm,Africa/Lusaka,Lusaka 38 | Africa/Malabo,Africa/Malabo,gq,Africa/Malabo,Malabo 39 | Africa/Maputo,Africa/Maputo,mz,Africa/Maputo,Maputo 40 | Africa/Maseru,Africa/Maseru,ls,Africa/Maseru,Maseru 41 | Africa/Mbabane,Africa/Mbabane,sz,Africa/Mbabane,Mbabane 42 | Africa/Mogadishu,Africa/Mogadishu,so,Africa/Mogadishu,Mogadishu 43 | Africa/Monrovia,Africa/Monrovia,lr,Africa/Monrovia,Monrovia 44 | Africa/Nairobi,Africa/Nairobi,ke,Africa/Nairobi,Nairobi 45 | Africa/Ndjamena,Africa/Ndjamena,td,Africa/Ndjamena,Ndjamena 46 | Africa/Niamey,Africa/Niamey,ne,Africa/Niamey,Niamey 47 | Africa/Nouakchott,Africa/Nouakchott,mr,Africa/Nouakchott,Nouakchott 48 | Africa/Ouagadougou,Africa/Ouagadougou,bf,Africa/Ouagadougou,Ouagadougou 49 | Africa/Porto-Novo,Africa/Porto-Novo,bj,Africa/Porto-Novo,Porto-Novo 50 | Africa/Sao_Tome,Africa/Sao_Tome,st,Africa/Sao Tome,Sao Tome 51 | Africa/Tripoli,Africa/Tripoli,ly,Africa/Tripoli,Tripoli 52 | Africa/Tunis,Africa/Tunis,tn,Africa/Tunis,Tunis 53 | Africa/Windhoek,Africa/Windhoek,na,Africa/Windhoek,Windhoek 54 | America/Adak,America/Adak,us,America/Adak,Adak 55 | America/Anchorage,America/Anchorage,us,America/Anchorage,Anchorage 56 | America/Anguilla,America/Anguilla,ai,America/Anguilla,Anguilla 57 | America/Antigua,America/Antigua,ag,America/Antigua,Antigua 58 | America/Araguaina,America/Araguaina,br,America/Araguaina,Araguaina 59 | America/Argentina/Buenos_Aires,America/Argentina/Buenos_Aires,ar,America/Argentina/Buenos Aires,Argentina/Buenos Aires 60 | America/Argentina/Catamarca,America/Argentina/Catamarca,ar,America/Argentina/Catamarca,Argentina/Catamarca 61 | America/Argentina/Cordoba,America/Argentina/Cordoba,ar,America/Argentina/Cordoba,Argentina/Cordoba 62 | America/Argentina/Jujuy,America/Argentina/Jujuy,ar,America/Argentina/Jujuy,Argentina/Jujuy 63 | America/Argentina/La_Rioja,America/Argentina/La_Rioja,ar,America/Argentina/La Rioja,Argentina/La Rioja 64 | America/Argentina/Mendoza,America/Argentina/Mendoza,ar,America/Argentina/Mendoza,Argentina/Mendoza 65 | America/Argentina/Rio_Gallegos,America/Argentina/Rio_Gallegos,ar,America/Argentina/Rio Gallegos,Argentina/Rio Gallegos 66 | America/Argentina/Salta,America/Argentina/Salta,ar,America/Argentina/Salta,Argentina/Salta 67 | America/Argentina/San_Juan,America/Argentina/San_Juan,ar,America/Argentina/San Juan,Argentina/San Juan 68 | America/Argentina/San_Luis,America/Argentina/San_Luis,ar,America/Argentina/San Luis,Argentina/San Luis 69 | America/Argentina/Tucuman,America/Argentina/Tucuman,ar,America/Argentina/Tucuman,Argentina/Tucuman 70 | America/Argentina/Ushuaia,America/Argentina/Ushuaia,ar,America/Argentina/Ushuaia,Argentina/Ushuaia 71 | America/Aruba,America/Aruba,aw,America/Aruba,Aruba 72 | America/Asuncion,America/Asuncion,py,America/Asuncion,Asuncion 73 | America/Atikokan,America/Atikokan,ca,America/Atikokan,Atikokan 74 | America/Bahia,America/Bahia,br,America/Bahia,Bahia 75 | America/Bahia_Banderas,America/Bahia_Banderas,mx,America/Bahia Banderas,Bahia Banderas 76 | America/Barbados,America/Barbados,bb,America/Barbados,Barbados 77 | America/Belem,America/Belem,br,America/Belem,Belem 78 | America/Belize,America/Belize,bz,America/Belize,Belize 79 | America/Blanc-Sablon,America/Blanc-Sablon,ca,America/Blanc-Sablon,Blanc-Sablon 80 | America/Boa_Vista,America/Boa_Vista,br,America/Boa Vista,Boa Vista 81 | America/Bogota,America/Bogota,co,America/Bogota,Bogota 82 | America/Boise,America/Boise,us,America/Boise,Boise 83 | America/Cambridge_Bay,America/Cambridge_Bay,ca,America/Cambridge Bay,Cambridge Bay 84 | America/Campo_Grande,America/Campo_Grande,br,America/Campo Grande,Campo Grande 85 | America/Cancun,America/Cancun,mx,America/Cancun,Cancun 86 | America/Caracas,America/Caracas,ve,America/Caracas,Caracas 87 | America/Cayenne,America/Cayenne,gf,America/Cayenne,Cayenne 88 | America/Cayman,America/Cayman,ky,America/Cayman,Cayman 89 | America/Chicago,America/Chicago,us,America/Chicago,Chicago 90 | America/Chihuahua,America/Chihuahua,mx,America/Chihuahua,Chihuahua 91 | America/Costa_Rica,America/Costa_Rica,cr,America/Costa Rica,Costa Rica 92 | America/Creston,America/Creston,ca,America/Creston,Creston 93 | America/Cuiaba,America/Cuiaba,br,America/Cuiaba,Cuiaba 94 | America/Curacao,America/Curacao,cw,America/Curacao,Curacao 95 | America/Danmarkshavn,America/Danmarkshavn,gl,America/Danmarkshavn,Danmarkshavn 96 | America/Dawson,America/Dawson,ca,America/Dawson,Dawson 97 | America/Dawson_Creek,America/Dawson_Creek,ca,America/Dawson Creek,Dawson Creek 98 | America/Denver,America/Denver,us,America/Denver,Denver 99 | America/Detroit,America/Detroit,us,America/Detroit,Detroit 100 | America/Dominica,America/Dominica,dm,America/Dominica,Dominica 101 | America/Edmonton,America/Edmonton,ca,America/Edmonton,Edmonton 102 | America/Eirunepe,America/Eirunepe,br,America/Eirunepe,Eirunepe 103 | America/El_Salvador,America/El_Salvador,sv,America/El Salvador,El Salvador 104 | America/Fort_Nelson,America/Fort_Nelson,ca,America/Fort Nelson,Fort Nelson 105 | America/Fortaleza,America/Fortaleza,br,America/Fortaleza,Fortaleza 106 | America/Glace_Bay,America/Glace_Bay,ca,America/Glace Bay,Glace Bay 107 | America/Goose_Bay,America/Goose_Bay,ca,America/Goose Bay,Goose Bay 108 | America/Grand_Turk,America/Grand_Turk,tc,America/Grand Turk,Grand Turk 109 | America/Grenada,America/Grenada,gd,America/Grenada,Grenada 110 | America/Guadeloupe,America/Guadeloupe,gp,America/Guadeloupe,Guadeloupe 111 | America/Guatemala,America/Guatemala,gt,America/Guatemala,Guatemala 112 | America/Guayaquil,America/Guayaquil,ec,America/Guayaquil,Guayaquil 113 | America/Guyana,America/Guyana,gy,America/Guyana,Guyana 114 | America/Halifax,America/Halifax,ca,America/Halifax,Halifax 115 | America/Havana,America/Havana,cu,America/Havana,Havana 116 | America/Hermosillo,America/Hermosillo,mx,America/Hermosillo,Hermosillo 117 | America/Indiana/Indianapolis,America/Indiana/Indianapolis,us,America/Indiana/Indianapolis,Indiana/Indianapolis 118 | America/Indiana/Knox,America/Indiana/Knox,us,America/Indiana/Knox,Indiana/Knox 119 | America/Indiana/Marengo,America/Indiana/Marengo,us,America/Indiana/Marengo,Indiana/Marengo 120 | America/Indiana/Petersburg,America/Indiana/Petersburg,us,America/Indiana/Petersburg,Indiana/Petersburg 121 | America/Indiana/Tell_City,America/Indiana/Tell_City,us,America/Indiana/Tell City,Indiana/Tell City 122 | America/Indiana/Vevay,America/Indiana/Vevay,us,America/Indiana/Vevay,Indiana/Vevay 123 | America/Indiana/Vincennes,America/Indiana/Vincennes,us,America/Indiana/Vincennes,Indiana/Vincennes 124 | America/Indiana/Winamac,America/Indiana/Winamac,us,America/Indiana/Winamac,Indiana/Winamac 125 | America/Inuvik,America/Inuvik,ca,America/Inuvik,Inuvik 126 | America/Iqaluit,America/Iqaluit,ca,America/Iqaluit,Iqaluit 127 | America/Jamaica,America/Jamaica,jm,America/Jamaica,Jamaica 128 | America/Juneau,America/Juneau,us,America/Juneau,Juneau 129 | America/Kentucky/Louisville,America/Kentucky/Louisville,us,America/Kentucky/Louisville,Kentucky/Louisville 130 | America/Kentucky/Monticello,America/Kentucky/Monticello,us,America/Kentucky/Monticello,Kentucky/Monticello 131 | America/Kralendijk,America/Kralendijk,bq,America/Kralendijk,Kralendijk 132 | America/La_Paz,America/La_Paz,bo,America/La Paz,La Paz 133 | America/Lima,America/Lima,pe,America/Lima,Lima 134 | America/Los_Angeles,America/Los_Angeles,us,America/Los Angeles,Los Angeles 135 | America/Lower_Princes,America/Lower_Princes,sx,America/Lower Princes,Lower Princes 136 | America/Maceio,America/Maceio,br,America/Maceio,Maceio 137 | America/Managua,America/Managua,ni,America/Managua,Managua 138 | America/Manaus,America/Manaus,br,America/Manaus,Manaus 139 | America/Marigot,America/Marigot,mf,America/Marigot,Marigot 140 | America/Martinique,America/Martinique,mq,America/Martinique,Martinique 141 | America/Matamoros,America/Matamoros,mx,America/Matamoros,Matamoros 142 | America/Mazatlan,America/Mazatlan,mx,America/Mazatlan,Mazatlan 143 | America/Menominee,America/Menominee,us,America/Menominee,Menominee 144 | America/Merida,America/Merida,mx,America/Merida,Merida 145 | America/Metlakatla,America/Metlakatla,us,America/Metlakatla,Metlakatla 146 | America/Mexico_City,America/Mexico_City,mx,America/Mexico City,Mexico City 147 | America/Miquelon,America/Miquelon,pm,America/Miquelon,Miquelon 148 | America/Moncton,America/Moncton,ca,America/Moncton,Moncton 149 | America/Monterrey,America/Monterrey,mx,America/Monterrey,Monterrey 150 | America/Montevideo,America/Montevideo,uy,America/Montevideo,Montevideo 151 | America/Montserrat,America/Montserrat,ms,America/Montserrat,Montserrat 152 | America/Nassau,America/Nassau,bs,America/Nassau,Nassau 153 | America/New_York,America/New_York,us,America/New York,New York 154 | America/Nipigon,America/Nipigon,ca,America/Nipigon,Nipigon 155 | America/Nome,America/Nome,us,America/Nome,Nome 156 | America/Noronha,America/Noronha,br,America/Noronha,Noronha 157 | America/North_Dakota/Beulah,America/North_Dakota/Beulah,us,America/North Dakota/Beulah,North Dakota/Beulah 158 | America/North_Dakota/Center,America/North_Dakota/Center,us,America/North Dakota/Center,North Dakota/Center 159 | America/North_Dakota/New_Salem,America/North_Dakota/New_Salem,us,America/North Dakota/New Salem,North Dakota/New Salem 160 | America/Nuuk,America/Nuuk,gl,America/Nuuk,Nuuk 161 | America/Ojinaga,America/Ojinaga,mx,America/Ojinaga,Ojinaga 162 | America/Panama,America/Panama,pa,America/Panama,Panama 163 | America/Pangnirtung,America/Pangnirtung,ca,America/Pangnirtung,Pangnirtung 164 | America/Paramaribo,America/Paramaribo,sr,America/Paramaribo,Paramaribo 165 | America/Phoenix,America/Phoenix,us,America/Phoenix,Phoenix 166 | America/Port-au-Prince,America/Port-au-Prince,ht,America/Port-au-Prince,Port-au-Prince 167 | America/Port_of_Spain,America/Port_of_Spain,tt,America/Port of Spain,Port of Spain 168 | America/Porto_Velho,America/Porto_Velho,br,America/Porto Velho,Porto Velho 169 | America/Puerto_Rico,America/Puerto_Rico,pr,America/Puerto Rico,Puerto Rico 170 | America/Punta_Arenas,America/Punta_Arenas,cl,America/Punta Arenas,Punta Arenas 171 | America/Rainy_River,America/Rainy_River,ca,America/Rainy River,Rainy River 172 | America/Rankin_Inlet,America/Rankin_Inlet,ca,America/Rankin Inlet,Rankin Inlet 173 | America/Recife,America/Recife,br,America/Recife,Recife 174 | America/Regina,America/Regina,ca,America/Regina,Regina 175 | America/Resolute,America/Resolute,ca,America/Resolute,Resolute 176 | America/Rio_Branco,America/Rio_Branco,br,America/Rio Branco,Rio Branco 177 | America/Santarem,America/Santarem,br,America/Santarem,Santarem 178 | America/Santiago,America/Santiago,cl,America/Santiago,Santiago 179 | America/Santo_Domingo,America/Santo_Domingo,do,America/Santo Domingo,Santo Domingo 180 | America/Sao_Paulo,America/Sao_Paulo,br,America/Sao Paulo,Sao Paulo 181 | America/Scoresbysund,America/Scoresbysund,gl,America/Scoresbysund,Scoresbysund 182 | America/Sitka,America/Sitka,us,America/Sitka,Sitka 183 | America/St_Barthelemy,America/St_Barthelemy,bl,America/St Barthelemy,St Barthelemy 184 | America/St_Johns,America/St_Johns,ca,America/St Johns,St Johns 185 | America/St_Kitts,America/St_Kitts,kn,America/St Kitts,St Kitts 186 | America/St_Lucia,America/St_Lucia,lc,America/St Lucia,St Lucia 187 | America/St_Thomas,America/St_Thomas,vi,America/St Thomas,St Thomas 188 | America/St_Vincent,America/St_Vincent,vc,America/St Vincent,St Vincent 189 | America/Swift_Current,America/Swift_Current,ca,America/Swift Current,Swift Current 190 | America/Tegucigalpa,America/Tegucigalpa,hn,America/Tegucigalpa,Tegucigalpa 191 | America/Thule,America/Thule,gl,America/Thule,Thule 192 | America/Thunder_Bay,America/Thunder_Bay,ca,America/Thunder Bay,Thunder Bay 193 | America/Tijuana,America/Tijuana,mx,America/Tijuana,Tijuana 194 | America/Toronto,America/Toronto,ca,America/Toronto,Toronto 195 | America/Tortola,America/Tortola,vg,America/Tortola,Tortola 196 | America/Vancouver,America/Vancouver,ca,America/Vancouver,Vancouver 197 | America/Whitehorse,America/Whitehorse,ca,America/Whitehorse,Whitehorse 198 | America/Winnipeg,America/Winnipeg,ca,America/Winnipeg,Winnipeg 199 | America/Yakutat,America/Yakutat,us,America/Yakutat,Yakutat 200 | America/Yellowknife,America/Yellowknife,ca,America/Yellowknife,Yellowknife 201 | Antarctica/Casey,Antarctica/Casey,aq,Antarctica/Casey,Casey 202 | Antarctica/Davis,Antarctica/Davis,aq,Antarctica/Davis,Davis 203 | Antarctica/DumontDUrville,Antarctica/DumontDUrville,aq,Antarctica/DumontDUrville,DumontDUrville 204 | Antarctica/Macquarie,Antarctica/Macquarie,au,Antarctica/Macquarie,Macquarie 205 | Antarctica/Mawson,Antarctica/Mawson,aq,Antarctica/Mawson,Mawson 206 | Antarctica/McMurdo,Antarctica/McMurdo,aq,Antarctica/McMurdo,McMurdo 207 | Antarctica/Palmer,Antarctica/Palmer,aq,Antarctica/Palmer,Palmer 208 | Antarctica/Rothera,Antarctica/Rothera,aq,Antarctica/Rothera,Rothera 209 | Antarctica/Syowa,Antarctica/Syowa,aq,Antarctica/Syowa,Syowa 210 | Antarctica/Troll,Antarctica/Troll,aq,Antarctica/Troll,Troll 211 | Antarctica/Vostok,Antarctica/Vostok,aq,Antarctica/Vostok,Vostok 212 | Arctic/Longyearbyen,Arctic/Longyearbyen,sj,Arctic/Longyearbyen,Longyearbyen 213 | Asia/Aden,Asia/Aden,ye,Asia/Aden,Aden 214 | Asia/Almaty,Asia/Almaty,kz,Asia/Almaty,Almaty 215 | Asia/Amman,Asia/Amman,jo,Asia/Amman,Amman 216 | Asia/Anadyr,Asia/Anadyr,ru,Asia/Anadyr,Anadyr 217 | Asia/Aqtau,Asia/Aqtau,kz,Asia/Aqtau,Aqtau 218 | Asia/Aqtobe,Asia/Aqtobe,kz,Asia/Aqtobe,Aqtobe 219 | Asia/Ashgabat,Asia/Ashgabat,tm,Asia/Ashgabat,Ashgabat 220 | Asia/Atyrau,Asia/Atyrau,kz,Asia/Atyrau,Atyrau 221 | Asia/Baghdad,Asia/Baghdad,iq,Asia/Baghdad,Baghdad 222 | Asia/Bahrain,Asia/Bahrain,bh,Asia/Bahrain,Bahrain 223 | Asia/Baku,Asia/Baku,az,Asia/Baku,Baku 224 | Asia/Bangkok,Asia/Bangkok,th,Asia/Bangkok,Bangkok 225 | Asia/Barnaul,Asia/Barnaul,ru,Asia/Barnaul,Barnaul 226 | Asia/Beirut,Asia/Beirut,lb,Asia/Beirut,Beirut 227 | Asia/Bishkek,Asia/Bishkek,kg,Asia/Bishkek,Bishkek 228 | Asia/Brunei,Asia/Brunei,bn,Asia/Brunei,Brunei 229 | Asia/Chita,Asia/Chita,ru,Asia/Chita,Chita 230 | Asia/Choibalsan,Asia/Choibalsan,mn,Asia/Choibalsan,Choibalsan 231 | Asia/Colombo,Asia/Colombo,lk,Asia/Colombo,Colombo 232 | Asia/Damascus,Asia/Damascus,sy,Asia/Damascus,Damascus 233 | Asia/Dhaka,Asia/Dhaka,bd,Asia/Dhaka,Dhaka 234 | Asia/Dili,Asia/Dili,tl,Asia/Dili,Dili 235 | Asia/Dubai,Asia/Dubai,ae,Asia/Dubai,Dubai 236 | Asia/Dushanbe,Asia/Dushanbe,tj,Asia/Dushanbe,Dushanbe 237 | Asia/Famagusta,Asia/Famagusta,cy,Asia/Famagusta,Famagusta 238 | Asia/Gaza,Asia/Gaza,ps,Asia/Gaza,Gaza 239 | Asia/Hebron,Asia/Hebron,ps,Asia/Hebron,Hebron 240 | Asia/Ho_Chi_Minh,Asia/Ho_Chi_Minh,vn,Asia/Ho Chi Minh,Ho Chi Minh 241 | Asia/Hong_Kong,Asia/Hong_Kong,hk,Asia/Hong Kong,Hong Kong 242 | Asia/Hovd,Asia/Hovd,mn,Asia/Hovd,Hovd 243 | Asia/Irkutsk,Asia/Irkutsk,ru,Asia/Irkutsk,Irkutsk 244 | Asia/Jakarta,Asia/Jakarta,id,Asia/Jakarta,Jakarta 245 | Asia/Jayapura,Asia/Jayapura,id,Asia/Jayapura,Jayapura 246 | Asia/Jerusalem,Asia/Jerusalem,il,Asia/Jerusalem,Jerusalem 247 | Asia/Kabul,Asia/Kabul,af,Asia/Kabul,Kabul 248 | Asia/Kamchatka,Asia/Kamchatka,ru,Asia/Kamchatka,Kamchatka 249 | Asia/Karachi,Asia/Karachi,pk,Asia/Karachi,Karachi 250 | Asia/Kathmandu,Asia/Kathmandu,np,Asia/Kathmandu,Kathmandu 251 | Asia/Khandyga,Asia/Khandyga,ru,Asia/Khandyga,Khandyga 252 | Asia/Kolkata,Asia/Kolkata,in,Asia/Kolkata,Kolkata 253 | Asia/Krasnoyarsk,Asia/Krasnoyarsk,ru,Asia/Krasnoyarsk,Krasnoyarsk 254 | Asia/Kuala_Lumpur,Asia/Kuala_Lumpur,my,Asia/Kuala Lumpur,Kuala Lumpur 255 | Asia/Kuching,Asia/Kuching,my,Asia/Kuching,Kuching 256 | Asia/Kuwait,Asia/Kuwait,kw,Asia/Kuwait,Kuwait 257 | Asia/Macau,Asia/Macau,mo,Asia/Macau,Macau 258 | Asia/Magadan,Asia/Magadan,ru,Asia/Magadan,Magadan 259 | Asia/Makassar,Asia/Makassar,id,Asia/Makassar,Makassar 260 | Asia/Manila,Asia/Manila,ph,Asia/Manila,Manila 261 | Asia/Muscat,Asia/Muscat,om,Asia/Muscat,Muscat 262 | Asia/Nicosia,Asia/Nicosia,cy,Asia/Nicosia,Nicosia 263 | Asia/Novokuznetsk,Asia/Novokuznetsk,ru,Asia/Novokuznetsk,Novokuznetsk 264 | Asia/Novosibirsk,Asia/Novosibirsk,ru,Asia/Novosibirsk,Novosibirsk 265 | Asia/Omsk,Asia/Omsk,ru,Asia/Omsk,Omsk 266 | Asia/Oral,Asia/Oral,kz,Asia/Oral,Oral 267 | Asia/Phnom_Penh,Asia/Phnom_Penh,kh,Asia/Phnom Penh,Phnom Penh 268 | Asia/Pontianak,Asia/Pontianak,id,Asia/Pontianak,Pontianak 269 | Asia/Pyongyang,Asia/Pyongyang,kp,Asia/Pyongyang,Pyongyang 270 | Asia/Qatar,Asia/Qatar,qa,Asia/Qatar,Qatar 271 | Asia/Qostanay,Asia/Qostanay,kz,Asia/Qostanay,Qostanay 272 | Asia/Qyzylorda,Asia/Qyzylorda,kz,Asia/Qyzylorda,Qyzylorda 273 | Asia/Riyadh,Asia/Riyadh,sa,Asia/Riyadh,Riyadh 274 | Asia/Sakhalin,Asia/Sakhalin,ru,Asia/Sakhalin,Sakhalin 275 | Asia/Samarkand,Asia/Samarkand,uz,Asia/Samarkand,Samarkand 276 | Asia/Seoul,Asia/Seoul,kr,Asia/Seoul,Seoul 277 | Asia/Shanghai,Asia/Shanghai,cn,Asia/Shanghai,Shanghai 278 | Asia/Singapore,Asia/Singapore,sg,Asia/Singapore,Singapore 279 | Asia/Srednekolymsk,Asia/Srednekolymsk,ru,Asia/Srednekolymsk,Srednekolymsk 280 | Asia/Taipei,Asia/Taipei,tw,Asia/Taipei,Taipei 281 | Asia/Tashkent,Asia/Tashkent,uz,Asia/Tashkent,Tashkent 282 | Asia/Tbilisi,Asia/Tbilisi,ge,Asia/Tbilisi,Tbilisi 283 | Asia/Tehran,Asia/Tehran,ir,Asia/Tehran,Tehran 284 | Asia/Thimphu,Asia/Thimphu,bt,Asia/Thimphu,Thimphu 285 | Asia/Tokyo,Asia/Tokyo,jp,Asia/Tokyo,Tokyo 286 | Asia/Tomsk,Asia/Tomsk,ru,Asia/Tomsk,Tomsk 287 | Asia/Ulaanbaatar,Asia/Ulaanbaatar,mn,Asia/Ulaanbaatar,Ulaanbaatar 288 | Asia/Urumqi,Asia/Urumqi,cn,Asia/Urumqi,Urumqi 289 | Asia/Ust-Nera,Asia/Ust-Nera,ru,Asia/Ust-Nera,Ust-Nera 290 | Asia/Vientiane,Asia/Vientiane,la,Asia/Vientiane,Vientiane 291 | Asia/Vladivostok,Asia/Vladivostok,ru,Asia/Vladivostok,Vladivostok 292 | Asia/Yakutsk,Asia/Yakutsk,ru,Asia/Yakutsk,Yakutsk 293 | Asia/Yangon,Asia/Yangon,mm,Asia/Yangon,Yangon 294 | Asia/Yekaterinburg,Asia/Yekaterinburg,ru,Asia/Yekaterinburg,Yekaterinburg 295 | Asia/Yerevan,Asia/Yerevan,am,Asia/Yerevan,Yerevan 296 | Atlantic/Azores,Atlantic/Azores,pt,Atlantic/Azores,Azores 297 | Atlantic/Bermuda,Atlantic/Bermuda,bm,Atlantic/Bermuda,Bermuda 298 | Atlantic/Canary,Atlantic/Canary,es,Atlantic/Canary,Canary 299 | Atlantic/Cape_Verde,Atlantic/Cape_Verde,cv,Atlantic/Cape Verde,Cape Verde 300 | Atlantic/Faroe,Atlantic/Faroe,fo,Atlantic/Faroe,Faroe 301 | Atlantic/Madeira,Atlantic/Madeira,pt,Atlantic/Madeira,Madeira 302 | Atlantic/Reykjavik,Atlantic/Reykjavik,is,Atlantic/Reykjavik,Reykjavik 303 | Atlantic/South_Georgia,Atlantic/South_Georgia,gs,Atlantic/South Georgia,South Georgia 304 | Atlantic/St_Helena,Atlantic/St_Helena,sh,Atlantic/St Helena,St Helena 305 | Atlantic/Stanley,Atlantic/Stanley,fk,Atlantic/Stanley,Stanley 306 | Australia/Adelaide,Australia/Adelaide,au,Australia/Adelaide,Adelaide 307 | Australia/Brisbane,Australia/Brisbane,au,Australia/Brisbane,Brisbane 308 | Australia/Broken_Hill,Australia/Broken_Hill,au,Australia/Broken Hill,Broken Hill 309 | Australia/Darwin,Australia/Darwin,au,Australia/Darwin,Darwin 310 | Australia/Eucla,Australia/Eucla,au,Australia/Eucla,Eucla 311 | Australia/Hobart,Australia/Hobart,au,Australia/Hobart,Hobart 312 | Australia/Lindeman,Australia/Lindeman,au,Australia/Lindeman,Lindeman 313 | Australia/Lord_Howe,Australia/Lord_Howe,au,Australia/Lord Howe,Lord Howe 314 | Australia/Melbourne,Australia/Melbourne,au,Australia/Melbourne,Melbourne 315 | Australia/Perth,Australia/Perth,au,Australia/Perth,Perth 316 | Australia/Sydney,Australia/Sydney,au,Australia/Sydney,Sydney 317 | Europe/Amsterdam,Europe/Amsterdam,nl,Europe/Amsterdam,Amsterdam 318 | Europe/Andorra,Europe/Andorra,ad,Europe/Andorra,Andorra 319 | Europe/Astrakhan,Europe/Astrakhan,ru,Europe/Astrakhan,Astrakhan 320 | Europe/Athens,Europe/Athens,gr,Europe/Athens,Athens 321 | Europe/Belgrade,Europe/Belgrade,rs,Europe/Belgrade,Belgrade 322 | Europe/Berlin,Europe/Berlin,de,Europe/Berlin,Berlin 323 | Europe/Bratislava,Europe/Bratislava,sk,Europe/Bratislava,Bratislava 324 | Europe/Brussels,Europe/Brussels,be,Europe/Brussels,Brussels 325 | Europe/Bucharest,Europe/Bucharest,ro,Europe/Bucharest,Bucharest 326 | Europe/Budapest,Europe/Budapest,hu,Europe/Budapest,Budapest 327 | Europe/Busingen,Europe/Busingen,de,Europe/Busingen,Busingen 328 | Europe/Chisinau,Europe/Chisinau,md,Europe/Chisinau,Chisinau 329 | Europe/Copenhagen,Europe/Copenhagen,dk,Europe/Copenhagen,Copenhagen 330 | Europe/Dublin,Europe/Dublin,ie,Europe/Dublin,Dublin 331 | Europe/Gibraltar,Europe/Gibraltar,gi,Europe/Gibraltar,Gibraltar 332 | Europe/Guernsey,Europe/Guernsey,gg,Europe/Guernsey,Guernsey 333 | Europe/Helsinki,Europe/Helsinki,fi,Europe/Helsinki,Helsinki 334 | Europe/Isle_of_Man,Europe/Isle_of_Man,im,Europe/Isle of Man,Isle of Man 335 | Europe/Istanbul,Europe/Istanbul,tr,Europe/Istanbul,Istanbul 336 | Europe/Jersey,Europe/Jersey,je,Europe/Jersey,Jersey 337 | Europe/Kaliningrad,Europe/Kaliningrad,ru,Europe/Kaliningrad,Kaliningrad 338 | Europe/Kiev,Europe/Kiev,ua,Europe/Kiev,Kiev 339 | Europe/Kirov,Europe/Kirov,ru,Europe/Kirov,Kirov 340 | Europe/Lisbon,Europe/Lisbon,pt,Europe/Lisbon,Lisbon 341 | Europe/Ljubljana,Europe/Ljubljana,si,Europe/Ljubljana,Ljubljana 342 | Europe/London,Europe/London,gb,Europe/London,London 343 | Europe/Luxembourg,Europe/Luxembourg,lu,Europe/Luxembourg,Luxembourg 344 | Europe/Madrid,Europe/Madrid,es,Europe/Madrid,Madrid 345 | Europe/Malta,Europe/Malta,mt,Europe/Malta,Malta 346 | Europe/Mariehamn,Europe/Mariehamn,ax,Europe/Mariehamn,Mariehamn 347 | Europe/Minsk,Europe/Minsk,by,Europe/Minsk,Minsk 348 | Europe/Monaco,Europe/Monaco,mc,Europe/Monaco,Monaco 349 | Europe/Moscow,Europe/Moscow,ru,Europe/Moscow,Moscow 350 | Europe/Oslo,Europe/Oslo,no,Europe/Oslo,Oslo 351 | Europe/Paris,Europe/Paris,fr,Europe/Paris,Paris 352 | Europe/Podgorica,Europe/Podgorica,me,Europe/Podgorica,Podgorica 353 | Europe/Prague,Europe/Prague,cz,Europe/Prague,Prague 354 | Europe/Riga,Europe/Riga,lv,Europe/Riga,Riga 355 | Europe/Rome,Europe/Rome,it,Europe/Rome,Rome 356 | Europe/Samara,Europe/Samara,ru,Europe/Samara,Samara 357 | Europe/San_Marino,Europe/San_Marino,sm,Europe/San Marino,San Marino 358 | Europe/Sarajevo,Europe/Sarajevo,ba,Europe/Sarajevo,Sarajevo 359 | Europe/Saratov,Europe/Saratov,ru,Europe/Saratov,Saratov 360 | Europe/Simferopol,Europe/Simferopol,ua,Europe/Simferopol,Simferopol 361 | Europe/Skopje,Europe/Skopje,mk,Europe/Skopje,Skopje 362 | Europe/Sofia,Europe/Sofia,bg,Europe/Sofia,Sofia 363 | Europe/Stockholm,Europe/Stockholm,se,Europe/Stockholm,Stockholm 364 | Europe/Tallinn,Europe/Tallinn,ee,Europe/Tallinn,Tallinn 365 | Europe/Tirane,Europe/Tirane,al,Europe/Tirane,Tirane 366 | Europe/Ulyanovsk,Europe/Ulyanovsk,ru,Europe/Ulyanovsk,Ulyanovsk 367 | Europe/Uzhgorod,Europe/Uzhgorod,ua,Europe/Uzhgorod,Uzhgorod 368 | Europe/Vaduz,Europe/Vaduz,li,Europe/Vaduz,Vaduz 369 | Europe/Vatican,Europe/Vatican,va,Europe/Vatican,Vatican 370 | Europe/Vienna,Europe/Vienna,at,Europe/Vienna,Vienna 371 | Europe/Vilnius,Europe/Vilnius,lt,Europe/Vilnius,Vilnius 372 | Europe/Volgograd,Europe/Volgograd,ru,Europe/Volgograd,Volgograd 373 | Europe/Warsaw,Europe/Warsaw,pl,Europe/Warsaw,Warsaw 374 | Europe/Zagreb,Europe/Zagreb,hr,Europe/Zagreb,Zagreb 375 | Europe/Zaporozhye,Europe/Zaporozhye,ua,Europe/Zaporozhye,Zaporozhye 376 | Europe/Zurich,Europe/Zurich,ch,Europe/Zurich,Zurich 377 | Indian/Antananarivo,Indian/Antananarivo,mg,Indian/Antananarivo,Antananarivo 378 | Indian/Chagos,Indian/Chagos,io,Indian/Chagos,Chagos 379 | Indian/Christmas,Indian/Christmas,cx,Indian/Christmas,Christmas 380 | Indian/Cocos,Indian/Cocos,cc,Indian/Cocos,Cocos 381 | Indian/Comoro,Indian/Comoro,km,Indian/Comoro,Comoro 382 | Indian/Kerguelen,Indian/Kerguelen,tf,Indian/Kerguelen,Kerguelen 383 | Indian/Mahe,Indian/Mahe,sc,Indian/Mahe,Mahe 384 | Indian/Maldives,Indian/Maldives,mv,Indian/Maldives,Maldives 385 | Indian/Mauritius,Indian/Mauritius,mu,Indian/Mauritius,Mauritius 386 | Indian/Mayotte,Indian/Mayotte,yt,Indian/Mayotte,Mayotte 387 | Indian/Reunion,Indian/Reunion,re,Indian/Reunion,Reunion 388 | Pacific/Apia,Pacific/Apia,ws,Pacific/Apia,Apia 389 | Pacific/Auckland,Pacific/Auckland,nz,Pacific/Auckland,Auckland 390 | Pacific/Bougainville,Pacific/Bougainville,pg,Pacific/Bougainville,Bougainville 391 | Pacific/Chatham,Pacific/Chatham,nz,Pacific/Chatham,Chatham 392 | Pacific/Chuuk,Pacific/Chuuk,fm,Pacific/Chuuk,Chuuk 393 | Pacific/Easter,Pacific/Easter,cl,Pacific/Easter,Easter 394 | Pacific/Efate,Pacific/Efate,vu,Pacific/Efate,Efate 395 | Pacific/Enderbury,Pacific/Enderbury,ki,Pacific/Enderbury,Enderbury 396 | Pacific/Fakaofo,Pacific/Fakaofo,tk,Pacific/Fakaofo,Fakaofo 397 | Pacific/Fiji,Pacific/Fiji,fj,Pacific/Fiji,Fiji 398 | Pacific/Funafuti,Pacific/Funafuti,tv,Pacific/Funafuti,Funafuti 399 | Pacific/Galapagos,Pacific/Galapagos,ec,Pacific/Galapagos,Galapagos 400 | Pacific/Gambier,Pacific/Gambier,pf,Pacific/Gambier,Gambier 401 | Pacific/Guadalcanal,Pacific/Guadalcanal,sb,Pacific/Guadalcanal,Guadalcanal 402 | Pacific/Guam,Pacific/Guam,gu,Pacific/Guam,Guam 403 | Pacific/Honolulu,Pacific/Honolulu,us,Pacific/Honolulu,Honolulu 404 | Pacific/Kiritimati,Pacific/Kiritimati,ki,Pacific/Kiritimati,Kiritimati 405 | Pacific/Kosrae,Pacific/Kosrae,fm,Pacific/Kosrae,Kosrae 406 | Pacific/Kwajalein,Pacific/Kwajalein,mh,Pacific/Kwajalein,Kwajalein 407 | Pacific/Majuro,Pacific/Majuro,mh,Pacific/Majuro,Majuro 408 | Pacific/Marquesas,Pacific/Marquesas,pf,Pacific/Marquesas,Marquesas 409 | Pacific/Midway,Pacific/Midway,um,Pacific/Midway,Midway 410 | Pacific/Nauru,Pacific/Nauru,nr,Pacific/Nauru,Nauru 411 | Pacific/Niue,Pacific/Niue,nu,Pacific/Niue,Niue 412 | Pacific/Norfolk,Pacific/Norfolk,nf,Pacific/Norfolk,Norfolk 413 | Pacific/Noumea,Pacific/Noumea,nc,Pacific/Noumea,Noumea 414 | Pacific/Pago_Pago,Pacific/Pago_Pago,as,Pacific/Pago Pago,Pago Pago 415 | Pacific/Palau,Pacific/Palau,pw,Pacific/Palau,Palau 416 | Pacific/Pitcairn,Pacific/Pitcairn,pn,Pacific/Pitcairn,Pitcairn 417 | Pacific/Pohnpei,Pacific/Pohnpei,fm,Pacific/Pohnpei,Pohnpei 418 | Pacific/Port_Moresby,Pacific/Port_Moresby,pg,Pacific/Port Moresby,Port Moresby 419 | Pacific/Rarotonga,Pacific/Rarotonga,ck,Pacific/Rarotonga,Rarotonga 420 | Pacific/Saipan,Pacific/Saipan,mp,Pacific/Saipan,Saipan 421 | Pacific/Tahiti,Pacific/Tahiti,pf,Pacific/Tahiti,Tahiti 422 | Pacific/Tarawa,Pacific/Tarawa,ki,Pacific/Tarawa,Tarawa 423 | Pacific/Tongatapu,Pacific/Tongatapu,to,Pacific/Tongatapu,Tongatapu 424 | Pacific/Wake,Pacific/Wake,um,Pacific/Wake,Wake 425 | Pacific/Wallis,Pacific/Wallis,wf,Pacific/Wallis,Wallis 426 | UTC,UTC,,Coordinated Universal Time,UTC -------------------------------------------------------------------------------- /packages/timezones-en/src/TimezonesEnServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'The selected :attribute is an invalid timezone.', 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/timezones/src/Models/Timezone.php: -------------------------------------------------------------------------------- 1 | 'string', 16 | 'code' => 'string', 17 | 'country_id' => 'string', 18 | 'long_name' => 'string', 19 | 'name' => 'string', 20 | ]; 21 | 22 | public static function getDefault(): ?static 23 | { 24 | return static::find(config('app.timezone')); 25 | } 26 | 27 | public function airports(): HasMany 28 | { 29 | return $this->hasMany(Airport::class); 30 | } 31 | 32 | public function continent(): HasOneThrough 33 | { 34 | return $this->hasOneThrough(Continent::class, Country::class); 35 | } 36 | 37 | public function country(): BelongsTo 38 | { 39 | return $this->belongsTo(Country::class); 40 | } 41 | 42 | public function getOffset(DateTimeInterface $dateTime): int|false|null 43 | { 44 | if (! $this->id) { 45 | return null; 46 | } 47 | 48 | return (new DateTimeZone($this->id))->getOffset($dateTime); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/timezones/src/Rules/TimezoneRule.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__ . '/../resources/lang', 'squire-timezones'); 12 | 13 | $this->publishes([ 14 | __DIR__ . '/../resources/lang' => resource_path('lang/vendor/squire-timezones'), 15 | ]); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests 6 | 7 | 8 | 9 | 10 | packages 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/ModelTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(2, Models\Foo::count()); 24 | $this->assertEquals('bar', Models\Foo::first()->foo); 25 | 26 | $this->testModel(Airline::class); 27 | $this->testModel(Airport::class); 28 | $this->testModel(Continent::class); 29 | $this->testModel(Country::class); 30 | $this->testModel(Currency::class); 31 | $this->testModel(GbCounty::class); 32 | $this->testModel(Region::class); 33 | $this->testModel(Timezone::class); 34 | } 35 | 36 | protected function testModel(string $model): void 37 | { 38 | $locales = array_keys(Repository::getSources($model)); 39 | 40 | foreach ($locales as $locale) { 41 | App::setLocale($locale); 42 | 43 | $model::clearBootedModels(); 44 | 45 | $this->assertIsObject($model::all()); 46 | } 47 | } 48 | 49 | /** @test */ 50 | public function can_translate_models(): void 51 | { 52 | Repository::registerSource(Models\Foo::class, 'en', __DIR__ . '/data/foo-en.csv'); 53 | Repository::registerSource(Models\Foo::class, 'es', __DIR__ . '/data/foo-es.csv'); 54 | 55 | App::setLocale('en'); 56 | $this->assertEquals('en', Models\Foo::first()->lang); 57 | 58 | Models\Foo::clearBootedModels(); 59 | 60 | App::setLocale('es'); 61 | $this->assertEquals('es', Models\Foo::first()->lang); 62 | } 63 | 64 | /** @test */ 65 | public function can_format_usd(): void 66 | { 67 | $this->assertSame('$5.00', Currency::find('usd')->format(500)); 68 | $this->assertSame('$500.00', Currency::find('usd')->format(500, true)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/Models/Foo.php: -------------------------------------------------------------------------------- 1 | 'string', 11 | 'lang' => 'string', 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /tests/RuleTest.php: -------------------------------------------------------------------------------- 1 | testRule(Rules\FooRule::class, Models\Foo::class); 33 | 34 | $this->testRule(AirlineRule::class, Airline::class); 35 | $this->testRule(AirportRule::class, Airport::class); 36 | $this->testRule(ContinentRule::class, Continent::class); 37 | $this->testRule(CountryRule::class, Country::class); 38 | $this->testRule(CurrencyRule::class, Currency::class); 39 | $this->testRule(GbCountyRule::class, GbCounty::class); 40 | $this->testRule(RegionRule::class, Region::class); 41 | $this->testRule(TimezoneRule::class, Timezone::class); 42 | } 43 | 44 | protected function testRule(string $rule, string $model): void 45 | { 46 | $primaryKey = array_keys($model::$schema)[0]; 47 | $secondaryKey = array_keys($model::$schema)[1]; 48 | 49 | $this->assertTrue(Validator::make([ 50 | $primaryKey => $model::first()->{$primaryKey}, 51 | $secondaryKey => $model::first()->{$secondaryKey}, 52 | ], [ 53 | $primaryKey => [new $rule()], 54 | $secondaryKey => [new $rule($secondaryKey)], 55 | ])->passes()); 56 | 57 | $this->assertTrue(Validator::make([ 58 | $primaryKey => null, 59 | $secondaryKey => null, 60 | ], [ 61 | $primaryKey => [new $rule()], 62 | $secondaryKey => [new $rule($secondaryKey)], 63 | ])->fails()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/Rules/FooRule.php: -------------------------------------------------------------------------------- 1 | filter(fn (string $name): bool => $this->isTranslatedPackageDirectory($name)) 16 | ->map(fn (string $name): string => str_replace(static::PACKAGES_DIRECTORY, '', $name)) 17 | ->groupBy(function (string $name): string { 18 | $parts = explode('-', $name); 19 | unset($parts[count($parts) - 1]); 20 | 21 | return implode('-', $parts); 22 | }) 23 | ->filter(fn (Collection $translations): bool => $translations->count() > 1) 24 | ->each(function (Collection $translations, string $package): void { 25 | $previous = null; 26 | 27 | $translations->each(function (string $translation) use ($package, &$previous) { 28 | $lines = count(explode('\n', file_get_contents(static::PACKAGES_DIRECTORY . $translation . '/resources/data.csv'))); 29 | 30 | if ($previous !== null) { 31 | $this->assertSame($lines, $previous, "Number of data entires in {$package} is not the same for translations ($translation)."); 32 | } 33 | 34 | $previous = $lines; 35 | }); 36 | }); 37 | } 38 | 39 | protected function isTranslatedPackageDirectory(string $name): bool 40 | { 41 | $parts = explode('-', $name); 42 | 43 | if (count($parts) <= 1) { 44 | return false; 45 | } 46 | 47 | return strlen($parts[count($parts) - 1]) === 2; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/data/foo-en.csv: -------------------------------------------------------------------------------- 1 | foo,lang 2 | bar,en 3 | baz,en -------------------------------------------------------------------------------- /tests/data/foo-es.csv: -------------------------------------------------------------------------------- 1 | foo,lang 2 | bar,es 3 | baz,es --------------------------------------------------------------------------------