From 4e36cf89ba067b44f24309c9ba377ea85a107524 Mon Sep 17 00:00:00 2001 From: david_smith Date: Mon, 14 Oct 2024 22:46:34 -0400 Subject: [PATCH] Let's change the world! --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++ .github/dependabot.yml | 6 + .github/pull_request_template.md | 1 + .github/workflows/phpunit.yml | 42 +++++++ .gitignore | 5 + CODE_OF_CONDUCT.md | 128 ++++++++++++++++++++++ CONTRIBUTING.md | 53 +++++++++ LICENSE.md | 21 ++++ README.md | 14 +++ SECURITY.md | 17 +++ composer.json | 38 +++++++ docker-compose.yml | 23 ++++ docker/php71/Dockerfile | 18 +++ docker/php71/php.ini | 0 phpunit.xml | 13 +++ src/Factory.php | 35 ++++++ tests/TestCase.php | 9 ++ tests/Unit/Context/ContextTest.php | 21 ++++ tests/Unit/Context/User.php | 20 ++++ tests/Unit/Context/UserFactory.php | 25 +++++ tests/Unit/DataModel.php | 16 +++ tests/Unit/Factory/FactoryTest.php | 21 ++++ tests/Unit/Factory/User.php | 20 ++++ tests/Unit/Factory/UserFactory.php | 25 +++++ tests/Unit/Method/FactoryTest.php | 23 ++++ tests/Unit/Method/User.php | 20 ++++ tests/Unit/Method/UserFactory.php | 30 +++++ tests/Unit/Override/OverrideTest.php | 23 ++++ tests/Unit/Override/User.php | 18 +++ tests/Unit/Override/UserFactory.php | 28 +++++ 31 files changed, 771 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/phpunit.yml create mode 100644 .gitignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 composer.json create mode 100644 docker-compose.yml create mode 100644 docker/php71/Dockerfile create mode 100644 docker/php71/php.ini create mode 100644 phpunit.xml create mode 100644 src/Factory.php create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/Context/ContextTest.php create mode 100644 tests/Unit/Context/User.php create mode 100644 tests/Unit/Context/UserFactory.php create mode 100644 tests/Unit/DataModel.php create mode 100644 tests/Unit/Factory/FactoryTest.php create mode 100644 tests/Unit/Factory/User.php create mode 100644 tests/Unit/Factory/UserFactory.php create mode 100644 tests/Unit/Method/FactoryTest.php create mode 100644 tests/Unit/Method/User.php create mode 100644 tests/Unit/Method/UserFactory.php create mode 100644 tests/Unit/Override/OverrideTest.php create mode 100644 tests/Unit/Override/User.php create mode 100644 tests/Unit/Override/UserFactory.php diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e9d271d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..5404702 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1 @@ +## Description \ No newline at end of file diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..3eb350f --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,42 @@ +name: PHPUnit Tests + +on: + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: write + +jobs: + phpunit: + runs-on: ubuntu-latest + + services: + docker: + image: docker:20.10.7 + options: --privileged + + steps: + - uses: actions/checkout@v4 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install Composer dependencies + run: docker compose run --rm php82composer composer install --prefer-dist --no-progress --no-suggest + + - name: Run PHPUnit tests + run: docker compose run --rm php82 vendor/bin/phpunit \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac1c4d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +vendor +.idea +composer.lock +.phpunit.result.cache +.php-cs-fixer.cache \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7b9d7bc --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +dave0016@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0e9e122 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,53 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..eb58c2e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) ZeroToProd + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0d6c72 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# `Zerotoprod\DataModelFactory` + +[![Repo](https://img.shields.io/badge/github-gray?logo=github)](https://github.com/zero-to-prod/data-model-factory) +[![Latest Version on Packagist](https://img.shields.io/packagist/v/zero-to-prod/data-model-factory.svg)](https://packagist.org/packages/zero-to-prod/data-model-factory) +![test](https://github.com/zero-to-prod/data-model-factory/actions/workflows/phpunit.yml/badge.svg) +![Downloads](https://img.shields.io/packagist/dt/zero-to-prod/data-model-factory.svg?style=flat-square)](https://packagist.org/packages/zero-to-prod/data-model-factory)) + +## Installation + +Install the package via Composer: + +```bash +composer require zero-to-prod/data-model-factory +``` \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..bca8188 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------| ------------------ | +| 8.2.x | :white_check_mark: | +| 8.1.x | :white_check_mark: | +| 8.0.x | :white_check_mark: | +| 7.4.x | :white_check_mark: | +| 7.3.x | :white_check_mark: | +| 7.2.x | :white_check_mark: | +| 7.1.x | :white_check_mark: | + +## Reporting a Vulnerability + +Email dave0016@gmail.com \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..19c0466 --- /dev/null +++ b/composer.json @@ -0,0 +1,38 @@ +{ + "type": "library", + "name": "zero-to-prod/data-model-factory", + "description": "Factory Trait for Instantiating a Class", + "keywords": [ + "zero-to-prod", + "data-model-factory" + ], + "homepage": "https://github.com/zero-to-prod/data-model-factory", + "license": "MIT", + "authors": [ + { + "name": "David Smith", + "email": "dave0016@gmail.com" + } + ], + "require": { + "php": ">=7.1.0" + }, + "autoload": { + "psr-4": { + "Zerotoprod\\DataModelFactory\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "zero-to-prod/transformable": "Transform a class into different types.", + "zero-to-prod/data-model-helper": "Helpers for a DataModel.", + "zero-to-prod/data-model": "Transform data into a class." + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cb785f7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +services: + php71: + build: + context: docker/php71 + target: base + volumes: + - ./:/app + - ./docker/php71:/usr/local/etc/php + + php71debug: + build: + context: docker/php71 + target: debug + volumes: + - ./:/app + + php71composer: + build: + context: docker/php71 + target: composer + volumes: + - ./:/app + - ./docker/php71:/usr/local/etc/php \ No newline at end of file diff --git a/docker/php71/Dockerfile b/docker/php71/Dockerfile new file mode 100644 index 0000000..03cffd1 --- /dev/null +++ b/docker/php71/Dockerfile @@ -0,0 +1,18 @@ +FROM php:7.1-cli AS base +WORKDIR /app +RUN apt-get update && apt-get install -y \ + git \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +FROM base AS composer +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +FROM base AS debug +RUN pecl channel-update pecl.php.net && \ + pecl install xdebug-2.9.8 && \ + docker-php-ext-enable xdebug && \ + echo "xdebug.mode=coverage" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \ +WORKDIR /app + +CMD ["bash"] \ No newline at end of file diff --git a/docker/php71/php.ini b/docker/php71/php.ini new file mode 100644 index 0000000..e69de29 diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..a28da54 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,13 @@ + + + + + ./tests + + + + + src + + + \ No newline at end of file diff --git a/src/Factory.php b/src/Factory.php new file mode 100644 index 0000000..c176714 --- /dev/null +++ b/src/Factory.php @@ -0,0 +1,35 @@ +context = $context; + } + + private function definition(): array + { + return []; + } + + private function instantiate() + { + return $this->model::from(array_merge($this->definition(), $this->context)); + } + + public function make() + { + return $this->instantiate(); + } + + private function state(array $state): self + { + $this->context = array_merge($this->context, $state); + + return $this; + } +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..32e9be6 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,9 @@ + 'Doe'])->make(); + + self::assertEquals('John', $User->first_name); + self::assertEquals('Doe', $User->last_name); + } +} \ No newline at end of file diff --git a/tests/Unit/Context/User.php b/tests/Unit/Context/User.php new file mode 100644 index 0000000..e5be911 --- /dev/null +++ b/tests/Unit/Context/User.php @@ -0,0 +1,20 @@ + 'John', + User::last_name => 'N/A' + ]; + } + + public function make(): User + { + return $this->instantiate(); + } +} \ No newline at end of file diff --git a/tests/Unit/DataModel.php b/tests/Unit/DataModel.php new file mode 100644 index 0000000..7d0cef0 --- /dev/null +++ b/tests/Unit/DataModel.php @@ -0,0 +1,16 @@ + $value) { + $self->{$key} = $value; + } + + return $self; + } +} \ No newline at end of file diff --git a/tests/Unit/Factory/FactoryTest.php b/tests/Unit/Factory/FactoryTest.php new file mode 100644 index 0000000..e9b77d1 --- /dev/null +++ b/tests/Unit/Factory/FactoryTest.php @@ -0,0 +1,21 @@ +make(); + + self::assertEquals('John', $User->first_name); + self::assertEquals('N/A', $User->last_name); + } +} \ No newline at end of file diff --git a/tests/Unit/Factory/User.php b/tests/Unit/Factory/User.php new file mode 100644 index 0000000..f35a508 --- /dev/null +++ b/tests/Unit/Factory/User.php @@ -0,0 +1,20 @@ + 'John', + User::last_name => 'N/A' + ]; + } + + public function make(): User + { + return $this->instantiate(); + } +} \ No newline at end of file diff --git a/tests/Unit/Method/FactoryTest.php b/tests/Unit/Method/FactoryTest.php new file mode 100644 index 0000000..4f1c9c8 --- /dev/null +++ b/tests/Unit/Method/FactoryTest.php @@ -0,0 +1,23 @@ +setFirstName('Jim') + ->make(); + + self::assertEquals('Jim', $User->first_name); + self::assertEquals('N/A', $User->last_name); + } +} \ No newline at end of file diff --git a/tests/Unit/Method/User.php b/tests/Unit/Method/User.php new file mode 100644 index 0000000..3d6e4e4 --- /dev/null +++ b/tests/Unit/Method/User.php @@ -0,0 +1,20 @@ + 'John', + User::last_name => 'N/A' + ]; + } + + public function setFirstName(string $value): self + { + return $this->state([User::first_name => $value]); + } + + public function make(): User + { + return $this->instantiate(); + } +} \ No newline at end of file diff --git a/tests/Unit/Override/OverrideTest.php b/tests/Unit/Override/OverrideTest.php new file mode 100644 index 0000000..019afe9 --- /dev/null +++ b/tests/Unit/Override/OverrideTest.php @@ -0,0 +1,23 @@ +setTime('2015-10-04 17:24:43.000000') + ->make(); + + self::assertInstanceOf(DateTime::class, $User->DateTime); + } +} \ No newline at end of file diff --git a/tests/Unit/Override/User.php b/tests/Unit/Override/User.php new file mode 100644 index 0000000..9a307da --- /dev/null +++ b/tests/Unit/Override/User.php @@ -0,0 +1,18 @@ +state([User::DateTime => $value]); + } + + private function instantiate() + { + return $this->model::from([User::DateTime => new DateTime($this->context['time'])]); + } + + public function make(): User + { + return $this->instantiate(); + } +} \ No newline at end of file