From d33c4c416d46591150cc09c39b897eafdad9c759 Mon Sep 17 00:00:00 2001 From: Osmar Queiroz Date: Thu, 4 May 2017 00:50:32 -0300 Subject: [PATCH 1/4] inicio --- .gitignore | 3 + bkp_sql.sql | 26 + cli-config.php | 7 + composer.json | 16 + composer.lock | 1246 +++++++++++++++++++++++++++++++ index.php | 26 + nbproject/project.properties | 8 + nbproject/project.xml | 9 + src/Entity/ApiKey.php | 35 + src/Entity/Product.php | 28 + src/Entity/User.php | 28 + src/Model/BaseModel.php | 8 + src/Route/BaseController.php | 9 + src/Route/ProductController.php | 17 + src/Route/UserController.php | 18 + 15 files changed, 1484 insertions(+) create mode 100644 .gitignore create mode 100644 bkp_sql.sql create mode 100644 cli-config.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 index.php create mode 100644 nbproject/project.properties create mode 100644 nbproject/project.xml create mode 100644 src/Entity/ApiKey.php create mode 100644 src/Entity/Product.php create mode 100644 src/Entity/User.php create mode 100644 src/Model/BaseModel.php create mode 100644 src/Route/BaseController.php create mode 100644 src/Route/ProductController.php create mode 100644 src/Route/UserController.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..856cac06 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor/ +/nbproject/private/ +store.sqlite3 \ No newline at end of file diff --git a/bkp_sql.sql b/bkp_sql.sql new file mode 100644 index 00000000..9efe6534 --- /dev/null +++ b/bkp_sql.sql @@ -0,0 +1,26 @@ +BEGIN TRANSACTION; +CREATE TABLE "user" ( + `user_id` INTEGER PRIMARY KEY AUTOINCREMENT, + `login` TEXT, + `password` TEXT, + `create_at` NUMERIC, + `update_at` NUMERIC +); +CREATE TABLE `product` ( + `product_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `description` BLOB NOT NULL, + `price` REAL DEFAULT '0.00', + `category` TEXT, + `create_at` NUMERIC, + `update_at` NUMERIC +); +CREATE TABLE `api_key` ( + `api_key_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `user_id` INTEGER, + `key` TEXT NOT NULL, + `create_at` NUMERIC NOT NULL, + `expire_at` NUMERIC NOT NULL, + FOREIGN KEY(user_id) REFERENCES user(user_id) +); +COMMIT; diff --git a/cli-config.php b/cli-config.php new file mode 100644 index 00000000..046fa6b6 --- /dev/null +++ b/cli-config.php @@ -0,0 +1,7 @@ +2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2016-10-29T11:16:17+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/coding-standard": "~0.1@dev", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2017-01-03T10:49:41+00:00" + }, + { + "name": "doctrine/common", + "version": "v2.7.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "930297026c8009a567ac051fd545bf6124150347" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/930297026c8009a567ac051fd545bf6124150347", + "reference": "930297026c8009a567ac051fd545bf6124150347", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": "~5.6|~7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2017-01-13T14:02:13+00:00" + }, + { + "name": "doctrine/dbal", + "version": "v2.5.12", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "7b9e911f9d8b30d43b96853dab26898c710d8f44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/7b9e911f9d8b30d43b96853dab26898c710d8f44", + "reference": "7b9e911f9d8b30d43b96853dab26898c710d8f44", + "shasum": "" + }, + "require": { + "doctrine/common": ">=2.4,<2.8-dev", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "symfony/console": "2.*||^3.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\DBAL\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2017-02-08T12:53:47+00:00" + }, + { + "name": "doctrine/inflector", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2015-11-06T14:35:42+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + }, + { + "name": "doctrine/orm", + "version": "v2.5.6", + "source": { + "type": "git", + "url": "https://github.com/doctrine/doctrine2.git", + "reference": "e6c434196c8ef058239aaa0724b4aadb0107940b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b", + "reference": "e6c434196c8ef058239aaa0724b4aadb0107940b", + "shasum": "" + }, + "require": { + "doctrine/cache": "~1.4", + "doctrine/collections": "~1.2", + "doctrine/common": ">=2.5-dev,<2.8-dev", + "doctrine/dbal": ">=2.5-dev,<2.6-dev", + "doctrine/instantiator": "~1.0.1", + "ext-pdo": "*", + "php": ">=5.4", + "symfony/console": "~2.5|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "symfony/yaml": "~2.3|~3.0" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine", + "bin/doctrine.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\ORM\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "orm" + ], + "time": "2016-12-18T15:42:34+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2015-09-11T15:10:35+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "silex/silex", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Silex.git", + "reference": "d5a9d9af14a1424ddecc3da481769cf64e7d3b34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Silex/zipball/d5a9d9af14a1424ddecc3da481769cf64e7d3b34", + "reference": "d5a9d9af14a1424ddecc3da481769cf64e7d3b34", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "pimple/pimple": "~3.0", + "symfony/event-dispatcher": "~2.8|^3.0", + "symfony/http-foundation": "~2.8|^3.0", + "symfony/http-kernel": "~2.8|^3.0", + "symfony/routing": "~2.8|^3.0" + }, + "replace": { + "silex/api": "self.version", + "silex/providers": "self.version" + }, + "require-dev": { + "doctrine/dbal": "~2.2", + "monolog/monolog": "^1.4.1", + "swiftmailer/swiftmailer": "~5", + "symfony/asset": "~2.8|^3.0", + "symfony/browser-kit": "~2.8|^3.0", + "symfony/config": "~2.8|^3.0", + "symfony/css-selector": "~2.8|^3.0", + "symfony/debug": "~2.8|^3.0", + "symfony/doctrine-bridge": "~2.8|^3.0", + "symfony/dom-crawler": "~2.8|^3.0", + "symfony/expression-language": "~2.8|^3.0", + "symfony/finder": "~2.8|^3.0", + "symfony/form": "~2.8|^3.0", + "symfony/intl": "~2.8|^3.0", + "symfony/monolog-bridge": "~2.8|^3.0", + "symfony/options-resolver": "~2.8|^3.0", + "symfony/phpunit-bridge": "^3.2", + "symfony/process": "~2.8|^3.0", + "symfony/security": "~2.8|^3.0", + "symfony/serializer": "~2.8|^3.0", + "symfony/translation": "~2.8|^3.0", + "symfony/twig-bridge": "~2.8|^3.0", + "symfony/validator": "~2.8|^3.0", + "symfony/var-dumper": "~2.8|^3.0", + "symfony/web-link": "^3.3", + "twig/twig": "~1.28|~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Silex\\": "src/Silex" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "The PHP micro-framework based on the Symfony Components", + "homepage": "http://silex.sensiolabs.org", + "keywords": [ + "microframework" + ], + "time": "2017-05-03T15:21:42+00:00" + }, + { + "name": "symfony/console", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38", + "reference": "a7a17e0c6c3c4d70a211f80782e4b90ddadeaa38", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/debug": "~2.8|~3.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/filesystem": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/filesystem": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2017-04-26T01:39:17+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "fd6eeee656a5a7b384d56f1072243fe1c0e81686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/fd6eeee656a5a7b384d56f1072243fe1c0e81686", + "reference": "fd6eeee656a5a7b384d56f1072243fe1c0e81686", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2017-04-19T20:17:50+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "b8a401f733b43251e1d088c589368b2a94155e40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b8a401f733b43251e1d088c589368b2a94155e40", + "reference": "b8a401f733b43251e1d088c589368b2a94155e40", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2017-05-01T14:58:48+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "9de6add7f731e5af7f5b2e9c0da365e43383ebef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9de6add7f731e5af7f5b2e9c0da365e43383ebef", + "reference": "9de6add7f731e5af7f5b2e9c0da365e43383ebef", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "symfony/expression-language": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2017-05-01T14:55:58+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "46e8b209abab55c072c47d72d5cd1d62c0585e05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/46e8b209abab55c072c47d72d5cd1d62c0585e05", + "reference": "46e8b209abab55c072c47d72d5cd1d62c0585e05", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0", + "symfony/debug": "~2.8|~3.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/http-foundation": "~2.8.13|~3.1.6|~3.2" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "symfony/browser-kit": "~2.8|~3.0", + "symfony/class-loader": "~2.8|~3.0", + "symfony/config": "~2.8|~3.0", + "symfony/console": "~2.8|~3.0", + "symfony/css-selector": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/dom-crawler": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/finder": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0", + "symfony/routing": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0", + "symfony/templating": "~2.8|~3.0", + "symfony/translation": "~2.8|~3.0", + "symfony/var-dumper": "~3.2" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/class-loader": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/finder": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "https://symfony.com", + "time": "2017-05-01T17:46:48+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-11-14T01:06:16+00:00" + }, + { + "name": "symfony/routing", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "5029745d6d463585e8b487dbc83d6333f408853a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/5029745d6d463585e8b487dbc83d6333f408853a", + "reference": "5029745d6d463585e8b487dbc83d6333f408853a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.2", + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/dependency-injection": "For loading routes from a service", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Routing Component", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2017-04-12T14:13:17+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/index.php b/index.php new file mode 100644 index 00000000..bed50be8 --- /dev/null +++ b/index.php @@ -0,0 +1,26 @@ + 'pdo_sqlite', + 'src' => $dsn, +); +$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode); +$entityManager = EntityManager::create($dbParams, $config); + + +$app = new Silex\Application(); + +$app->mount("/", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."BaseController.php"); +$app->mount("/users", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."UserController.php"); +$app->mount("/products", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."ProductController.php"); + +$app->run(); \ No newline at end of file diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 00000000..46ccf393 --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,8 @@ +auxiliary.org-netbeans-modules-php-doctrine2.enabled=true +include.path=${php.global.include.path} +php.version=PHP_56 +source.encoding=UTF-8 +src.dir=. +tags.asp=false +tags.short=false +web.root=. diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 00000000..0bc49495 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,9 @@ + + + org.netbeans.modules.php.project + + + testeapi + + + diff --git a/src/Entity/ApiKey.php b/src/Entity/ApiKey.php new file mode 100644 index 00000000..57eebb6f --- /dev/null +++ b/src/Entity/ApiKey.php @@ -0,0 +1,35 @@ +get('/', function () { + return 'teste'; +}); + +return $base; diff --git a/src/Route/ProductController.php b/src/Route/ProductController.php new file mode 100644 index 00000000..b096454b --- /dev/null +++ b/src/Route/ProductController.php @@ -0,0 +1,17 @@ +before(function (Request $request, Application $app) { + +}); +$product->get('/', function () { return 'all'; }); +$product->get('/:id', function () { return 'especific';}); +$product->post('/', function () { return 'all'; }); +$product->put('/:id', function () { return 'especific';}); +$product->delete('/:id', function () { return 'especific';}); + +return $product; diff --git a/src/Route/UserController.php b/src/Route/UserController.php new file mode 100644 index 00000000..534ae06c --- /dev/null +++ b/src/Route/UserController.php @@ -0,0 +1,18 @@ +before(function (Request $request, Application $app) { + +}); + +$user->get('/', function () {return 'test';}); +$user->post('/', function () {return 'test';}); +$user->post('/authenticate', function () {return 'test';}); +$user->put('/:id', function () {return 'test';}); +$user->delete('/:id', function () {return 'test';}); + +return $user; From 29677bbafa37a70e4108963b431b202790485f23 Mon Sep 17 00:00:00 2001 From: Osmar Queiroz Date: Thu, 4 May 2017 04:53:00 -0300 Subject: [PATCH 2/4] =?UTF-8?q?criando=20conex=C3=A3o=20dos=20dados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- bkp_sql.sql | 8 +-- cli-config.php | 2 +- composer.json | 5 +- composer.lock | 73 ++++++++++++++++++++++++++- index.php | 13 +++-- src/Entity/ApiKey.php | 30 ++++++----- src/Entity/Product.php | 83 ++++++++++++++++++++++++++++--- src/Entity/User.php | 67 ++++++++++++++++++++++--- src/Entity/UserListener.php | 17 +++++++ src/Model/BaseModel.php | 8 --- src/Repository/UserRepository.php | 23 +++++++++ src/Route/BaseController.php | 19 ++++++- 13 files changed, 301 insertions(+), 49 deletions(-) create mode 100644 src/Entity/UserListener.php delete mode 100644 src/Model/BaseModel.php create mode 100644 src/Repository/UserRepository.php diff --git a/.gitignore b/.gitignore index 856cac06..3ec25333 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /vendor/ /nbproject/private/ -store.sqlite3 \ No newline at end of file +/db/store.db diff --git a/bkp_sql.sql b/bkp_sql.sql index 9efe6534..dc29cbde 100644 --- a/bkp_sql.sql +++ b/bkp_sql.sql @@ -1,13 +1,13 @@ BEGIN TRANSACTION; CREATE TABLE "user" ( - `user_id` INTEGER PRIMARY KEY AUTOINCREMENT, + `id` INTEGER PRIMARY KEY AUTOINCREMENT, `login` TEXT, `password` TEXT, `create_at` NUMERIC, `update_at` NUMERIC ); CREATE TABLE `product` ( - `product_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `description` BLOB NOT NULL, `price` REAL DEFAULT '0.00', @@ -16,11 +16,11 @@ CREATE TABLE `product` ( `update_at` NUMERIC ); CREATE TABLE `api_key` ( - `api_key_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `user_id` INTEGER, `key` TEXT NOT NULL, `create_at` NUMERIC NOT NULL, `expire_at` NUMERIC NOT NULL, - FOREIGN KEY(user_id) REFERENCES user(user_id) + FOREIGN KEY(user_id) REFERENCES user(id) ); COMMIT; diff --git a/cli-config.php b/cli-config.php index 046fa6b6..5db863ca 100644 --- a/cli-config.php +++ b/cli-config.php @@ -4,4 +4,4 @@ require_once 'index.php'; -return ConsoleRunner::createHelperSet($entityManager); \ No newline at end of file +return ConsoleRunner::createHelperSet($em); diff --git a/composer.json b/composer.json index 78a63573..c568bf7b 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,8 @@ { "name": "osmar/testeapi", + "require-dev":{ + "symfony/var-dumper":"*" + }, "require": { "silex/silex": "^2.1", "doctrine/orm": "^2.5" @@ -11,6 +14,6 @@ } ], "autoload" :{ - "psr-4" :{"Base\\":"src"} + "psr-4" :{"":"src/"} } } diff --git a/composer.lock b/composer.lock index 58acb220..45ff4b68 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "c069976ea76f0800341eaec7d41b014a", + "content-hash": "b2c7b1a361265c82c427b89de3c26b5c", "packages": [ { "name": "doctrine/annotations", @@ -1235,7 +1235,76 @@ "time": "2017-04-12T14:13:17+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "symfony/var-dumper", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "fa47963ac7979ddbd42b2d646d1b056bddbf7bb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/fa47963ac7979ddbd42b2d646d1b056bddbf7bb8", + "reference": "fa47963ac7979ddbd42b2d646d1b056bddbf7bb8", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + }, + "require-dev": { + "ext-iconv": "*", + "twig/twig": "~1.20|~2.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2017-05-01T14:55:58+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], diff --git a/index.php b/index.php index bed50be8..ad2f2f34 100644 --- a/index.php +++ b/index.php @@ -5,20 +5,23 @@ use Doctrine\ORM\EntityManager; -$dsn = __DIR__.DIRECTORY_SEPARATOR.'store.sqlite3'; -$paths = array(DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Entity'); +//$dsn = __DIR__.DIRECTORY_SEPARATOR.'baseDados.sqlite3'; +$dsn = __DIR__.DIRECTORY_SEPARATOR.'db'.DIRECTORY_SEPARATOR.'store.db'; +$paths = array(__DIR__.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Entity'); $isDevMode = false; $dbParams = array( 'driver' => 'pdo_sqlite', - 'src' => $dsn, + 'path' => $dsn, ); + $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode); -$entityManager = EntityManager::create($dbParams, $config); +$em = EntityManager::create($dbParams, $config); +//dump($em); $app = new Silex\Application(); - +$app['debug'] = true; $app->mount("/", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."BaseController.php"); $app->mount("/users", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."UserController.php"); $app->mount("/products", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."ProductController.php"); diff --git a/src/Entity/ApiKey.php b/src/Entity/ApiKey.php index 57eebb6f..d38418a1 100644 --- a/src/Entity/ApiKey.php +++ b/src/Entity/ApiKey.php @@ -8,28 +8,34 @@ * @Table(name="api_key") */ class ApiKey { - - /** + + /** * @GeneratedValue(strategy="IDENTITY") - * @Column(type="integer", unique=true,IDENTITY) + * @Id @Column(type="integer", unique=true) */ - protected $id; + protected $id; + /** * @GeneratedValue(strategy="UUID") * @Column(type="string", unique=true) */ protected $key; - - /** + + /** * @Column(type="integer") * @ManyToOne(targetEntity="User") * @JoinColumn(name="user_id", referencedColumnName="id") */ private $user; - - /** @Column(type="datetime") */ - protected $create_at; - - /** @Column(type="datetime") */ - protected $update_at; + + /** + * @Column(type="datetime") + */ + protected $createdAt; + + /** + * @Column(type="datetime") + */ + protected $updatedAt; + } diff --git a/src/Entity/Product.php b/src/Entity/Product.php index 6e2eb3c0..7f956633 100644 --- a/src/Entity/Product.php +++ b/src/Entity/Product.php @@ -7,22 +7,91 @@ * @Table(name="product") */ class Product { - + /** * @GeneratedValue(strategy="IDENTITY") - * @Column(type="integer", unique=true,IDENTITY) + * @Id @Column(type="integer", unique=true) */ protected $id; + /** @Column(type="string") */ protected $name; + /** @Column(type="text") */ protected $description; + /** @Column(type="decimal") */ - protected $price; + protected $price; + /** @Column(type="string") */ protected $category; - /** @Column(type="datetime") */ - protected $create_at; - /** @Column(type="datetime") */ - protected $update_at; + + /** + * @Column(type="datetime") + */ + protected $createdAt; + + /** + * @Column(type="datetime") + */ + protected $updatedAt; + + public function getId() { + return $this->id; + } + + public function getName() { + return $this->name; + } + + public function getDescription() { + return $this->description; + } + + public function getPrice() { + return $this->price; + } + + public function getCategory() { + return $this->category; + } + + public function getCreatedAt() { + return $this->createdAt; + } + + public function getUpdatedAt() { + return $this->updatedAt; + } + + public function setId($id) { + $this->id = $id; + } + + public function setName($name) { + $this->name = $name; + } + + public function setDescription($description) { + $this->description = $description; + } + + public function setPrice($price) { + $this->price = $price; + } + + public function setCategory($category) { + $this->category = $category; + } + + public function setCreatedAt($createdAt) { + $this->createdAt = $createdAt; + } + + public function setUpdatedAt($updatedAt) { + $this->updatedAt = $updatedAt; + } + + + } diff --git a/src/Entity/User.php b/src/Entity/User.php index 7651e8bb..c3707b18 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -3,14 +3,14 @@ namespace Entity; /** - * @Entity + * @Entity @EntityListeners({"UserListener"}) * @Table(name="user") */ class User { /** * @GeneratedValue(strategy="IDENTITY") - * @Column(type="integer", unique=true,IDENTITY) */ + * @Id @Column(type="integer", unique=true) */ protected $id; /** @Column(type="string", length=80) */ @@ -19,10 +19,65 @@ class User { /** @Column(type="string", length=20) */ protected $password; - /** @Column(type="datetime") */ - protected $createAt; + /** + * @Column(type="datetime") + */ + protected $createdAt; + + /** + * @Column(type="datetime") + */ + protected $updatedAt; + + public function getId() { + return $this->id; + } + + public function getLogin() { + return $this->login; + } + + public function getPassword() { + return $this->password; + } + + public function getCreatedAt() { + return $this->createdAt; + } + + public function getUpdatedAt() { + return $this->updatedAt; + } + + public function setId($id) { + $this->id = $id; + } + + public function setLogin($login) { + $this->login = $login; + } + + public function setPassword($password) { + $this->password = $password; + } + + public function setCreatedAt($createdAt) { + $this->createdAt = $createdAt; + } + + public function setUpdatedAt($updatedAt) { + $this->updatedAt = $updatedAt; + } + + + public function updatedTimestamps() +{ + $this->setUpdatedAt(new \DateTime('now')); + + if ($this->getCreatedAt() == null) { + $this->setCreatedAt(new \DateTime('now')); + } +} - /** @Column(type="datetime") */ - protected $updateAt; } diff --git a/src/Entity/UserListener.php b/src/Entity/UserListener.php new file mode 100644 index 00000000..14c19475 --- /dev/null +++ b/src/Entity/UserListener.php @@ -0,0 +1,17 @@ +updatedTimestamps(); + return $user; + } + +} diff --git a/src/Model/BaseModel.php b/src/Model/BaseModel.php deleted file mode 100644 index 3ac00faa..00000000 --- a/src/Model/BaseModel.php +++ /dev/null @@ -1,8 +0,0 @@ - + + } +} diff --git a/src/Route/BaseController.php b/src/Route/BaseController.php index 6254af5e..07b0af22 100644 --- a/src/Route/BaseController.php +++ b/src/Route/BaseController.php @@ -1,9 +1,24 @@ get('/', function () { - return 'teste'; + + +$base->get('/', function () use ($em) { + + $user = new \Entity\User(); + $user->setLogin("Loko de droga"); + $user->setPassword("loko"); + + $em->persist($user); + $em->flush(); + +// dump($app['db']['event_manager']->persist($user)); +// dump( ); + + return false; }); return $base; From 7b2201135413e402f59374eca90342f0b30b6041 Mon Sep 17 00:00:00 2001 From: Osmar Queiroz Date: Thu, 4 May 2017 18:23:50 -0300 Subject: [PATCH 3/4] create api e all methods --- .htaccess | 9 ++ cli-config.php | 2 +- composer.json | 3 +- composer.lock | 77 ++++++++++++++++- index.php | 6 +- src/Entity/ApiKey.php | 60 +++++++++++++- src/Entity/ApiKeyListener.php | 15 ++++ src/Entity/Product.php | 8 +- src/Entity/ProductListener.php | 15 ++++ src/Entity/User.php | 19 ++--- src/Entity/UserListener.php | 11 +-- src/Repository/ApiKeyRepository.php | 18 ++++ src/Repository/ProductRepository.php | 22 +++++ src/Repository/UserRepository.php | 25 +++--- src/Route/BaseController.php | 19 +++-- src/Route/ProductController.php | 118 +++++++++++++++++++++++++-- src/Route/UserController.php | 100 ++++++++++++++++++++--- 17 files changed, 462 insertions(+), 65 deletions(-) create mode 100644 .htaccess create mode 100644 src/Entity/ApiKeyListener.php create mode 100644 src/Entity/ProductListener.php create mode 100644 src/Repository/ApiKeyRepository.php create mode 100644 src/Repository/ProductRepository.php diff --git a/.htaccess b/.htaccess new file mode 100644 index 00000000..d1b713a6 --- /dev/null +++ b/.htaccess @@ -0,0 +1,9 @@ + + Options -MultiViews + + RewriteEngine On + #RewriteBase /path/to/app + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [QSA,L] + \ No newline at end of file diff --git a/cli-config.php b/cli-config.php index 5db863ca..7557e003 100644 --- a/cli-config.php +++ b/cli-config.php @@ -4,4 +4,4 @@ require_once 'index.php'; -return ConsoleRunner::createHelperSet($em); +return ConsoleRunner::createHelperSet($entityManager); diff --git a/composer.json b/composer.json index c568bf7b..5daa8946 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,8 @@ }, "require": { "silex/silex": "^2.1", - "doctrine/orm": "^2.5" + "doctrine/orm": "^2.5", + "symfony/serializer": "^3.2" }, "authors": [ { diff --git a/composer.lock b/composer.lock index 45ff4b68..4b3657dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "b2c7b1a361265c82c427b89de3c26b5c", + "content-hash": "271f01d900d079fa6b0b0e6734e92f5c", "packages": [ { "name": "doctrine/annotations", @@ -1233,6 +1233,81 @@ "url" ], "time": "2017-04-12T14:13:17+00:00" + }, + { + "name": "symfony/serializer", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "6eeae1ba82005b761a53b7b8cf960bbf40c95986" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/6eeae1ba82005b761a53b7b8cf960bbf40c95986", + "reference": "6eeae1ba82005b761a53b7b8cf960bbf40c95986", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "symfony/property-access": ">=3.0,<3.0.4|>=2.8,<2.8.4", + "symfony/property-info": "<3.1", + "symfony/yaml": "<3.1" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0", + "phpdocumentor/reflection-docblock": "~3.0", + "symfony/cache": "~3.1", + "symfony/config": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0", + "symfony/property-access": "~2.8|~3.0", + "symfony/property-info": "~3.1", + "symfony/yaml": "~3.1" + }, + "suggest": { + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "psr/cache-implementation": "For using the metadata cache.", + "symfony/config": "For using the XML mapping loader.", + "symfony/http-foundation": "To use the DataUriNormalizer.", + "symfony/property-access": "For using the ObjectNormalizer.", + "symfony/property-info": "To deserialize relations.", + "symfony/yaml": "For using the default YAML mapping loader." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Serializer Component", + "homepage": "https://symfony.com", + "time": "2017-05-01T14:55:58+00:00" } ], "packages-dev": [ diff --git a/index.php b/index.php index ad2f2f34..3b8f9b00 100644 --- a/index.php +++ b/index.php @@ -16,12 +16,16 @@ ); $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode); -$em = EntityManager::create($dbParams, $config); +$entityManager = EntityManager::create($dbParams, $config); //dump($em); $app = new Silex\Application(); $app['debug'] = true; +$app['db'] = $entityManager; +//$app->register(new Silex\Provider\ValidatorServiceProvider()); +$app->register(new Silex\Provider\SerializerServiceProvider()); + $app->mount("/", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."BaseController.php"); $app->mount("/users", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."UserController.php"); $app->mount("/products", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."ProductController.php"); diff --git a/src/Entity/ApiKey.php b/src/Entity/ApiKey.php index d38418a1..8534d69e 100644 --- a/src/Entity/ApiKey.php +++ b/src/Entity/ApiKey.php @@ -4,8 +4,10 @@ /** * + * @Entity(repositoryClass="Repository\ApiKeyRepository") @EntityListeners({"ApiKeyListener"}) * @Entity * @Table(name="api_key") + * */ class ApiKey { @@ -16,7 +18,7 @@ class ApiKey { protected $id; /** - * @GeneratedValue(strategy="UUID") + * * @Column(type="string", unique=true) */ protected $key; @@ -26,7 +28,7 @@ class ApiKey { * @ManyToOne(targetEntity="User") * @JoinColumn(name="user_id", referencedColumnName="id") */ - private $user; + private $user_id; /** * @Column(type="datetime") @@ -38,4 +40,58 @@ class ApiKey { */ protected $updatedAt; + public function getId() { + return $this->id; + } + + public function getKey() { + return $this->key; + } + + public function getUser_id() { + return $this->user_id; + } + + public function getCreatedAt() { + return $this->createdAt; + } + + public function getUpdatedAt() { + return $this->updatedAt; + } + + public function setId($id) { + $this->id = $id; + } + + public function setKey($key) { + $this->key = $key; + } + + public function setUser_id($user_id) { + $this->user_id = $user_id; + } + + public function setCreatedAt($createdAt) { + $this->createdAt = $createdAt; + } + + public function setUpdatedAt($updatedAt) { + $this->updatedAt = $updatedAt; + } + + public function updatedTimestamps() { + $this->setUpdatedAt(new \DateTime('now')); + + if ($this->getCreatedAt() == null) { + $this->setCreatedAt(new \DateTime('now')); + } + } + + public function createKey(){ + if ($this->getKey() == null) { + $this->setKey(uniqid("key_",true)); + } + } + } diff --git a/src/Entity/ApiKeyListener.php b/src/Entity/ApiKeyListener.php new file mode 100644 index 00000000..8806a97a --- /dev/null +++ b/src/Entity/ApiKeyListener.php @@ -0,0 +1,15 @@ +createKey(); + $apikey->updatedTimestamps(); + return $apikey; + } + +} diff --git a/src/Entity/Product.php b/src/Entity/Product.php index 7f956633..18fd7d75 100644 --- a/src/Entity/Product.php +++ b/src/Entity/Product.php @@ -3,7 +3,7 @@ namespace Entity; /** - * @Entity + * @Entity(repositoryClass="Repository\ProductRepository") @EntityListeners({"ProductListener"}) * @Table(name="product") */ class Product { @@ -92,6 +92,12 @@ public function setUpdatedAt($updatedAt) { $this->updatedAt = $updatedAt; } + public function updatedTimestamps() { + $this->setUpdatedAt(new \DateTime('now')); + if ($this->getCreatedAt() == null) { + $this->setCreatedAt(new \DateTime('now')); + } + } } diff --git a/src/Entity/ProductListener.php b/src/Entity/ProductListener.php new file mode 100644 index 00000000..4f603687 --- /dev/null +++ b/src/Entity/ProductListener.php @@ -0,0 +1,15 @@ +updatedTimestamps(); + return $product; + } + +} diff --git a/src/Entity/User.php b/src/Entity/User.php index c3707b18..dd65e808 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -3,7 +3,7 @@ namespace Entity; /** - * @Entity @EntityListeners({"UserListener"}) + * @Entity(repositoryClass="Repository\UserRepository") @EntityListeners({"UserListener"}) * @Table(name="user") */ class User { @@ -23,12 +23,12 @@ class User { * @Column(type="datetime") */ protected $createdAt; - + /** * @Column(type="datetime") */ protected $updatedAt; - + public function getId() { return $this->id; } @@ -69,15 +69,12 @@ public function setUpdatedAt($updatedAt) { $this->updatedAt = $updatedAt; } - - public function updatedTimestamps() -{ - $this->setUpdatedAt(new \DateTime('now')); + public function updatedTimestamps() { + $this->setUpdatedAt(new \DateTime('now')); - if ($this->getCreatedAt() == null) { - $this->setCreatedAt(new \DateTime('now')); + if ($this->getCreatedAt() == null) { + $this->setCreatedAt(new \DateTime('now')); + } } -} - } diff --git a/src/Entity/UserListener.php b/src/Entity/UserListener.php index 14c19475..224ff171 100644 --- a/src/Entity/UserListener.php +++ b/src/Entity/UserListener.php @@ -6,12 +6,13 @@ class UserListener { - - public function preFlush(User $user) { - - $user->updatedTimestamps(); - return $user; + $password = $user->getPassword(); + if (strlen($password) < 60) { + $user->setPassword(password_hash($password,PASSWORD_DEFAULT)); + } + $user->updatedTimestamps(); + return $user; } } diff --git a/src/Repository/ApiKeyRepository.php b/src/Repository/ApiKeyRepository.php new file mode 100644 index 00000000..288d1fa3 --- /dev/null +++ b/src/Repository/ApiKeyRepository.php @@ -0,0 +1,18 @@ +findOneBy(["user_id" => $user_id], ['id' => "desc"]); + } + + public function findOneByKey($key) { + return $this->findOneBy(["key" => $key]); + } + +} diff --git a/src/Repository/ProductRepository.php b/src/Repository/ProductRepository.php new file mode 100644 index 00000000..b5b50239 --- /dev/null +++ b/src/Repository/ProductRepository.php @@ -0,0 +1,22 @@ +findAll(); + } + + public function findProductByName($name) { + return $this->findOneBy(['name' => $name]); + } + public function findById($id) { + return $this->findOneBy(['id' => $id]); + } + +} diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index 63c3f719..250173dd 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -2,22 +2,19 @@ namespace Repository; - use Doctrine\ORM\EntityRepository; -use \Entity\User; +use Entity\User; -/** - * Description of UserRepository - * - * @author osmar - */ class UserRepository extends EntityRepository { - //put your code here - - public function findAllUsers(){ - -// $user = User(); -// $user-> - + + public function findAllUsers() { + return $this->findAll(); + } + + public function findUser($login) { + return $this->findOneBy(['login' => $login]); } + + + } diff --git a/src/Route/BaseController.php b/src/Route/BaseController.php index 07b0af22..d44773ac 100644 --- a/src/Route/BaseController.php +++ b/src/Route/BaseController.php @@ -6,17 +6,18 @@ -$base->get('/', function () use ($em) { - - $user = new \Entity\User(); - $user->setLogin("Loko de droga"); - $user->setPassword("loko"); - - $em->persist($user); - $em->flush(); +$base->get('/', function () use ($entityManager) { + +// $user = new \Entity\User(); +// $user->setLogin("Loko de droga"); +// $user->setPassword("loko"); +// +// $em->persist($user); +// $em->flush(); +// $dados =$entityManager->getRepository("Entity\User")->findUser('osmar'); // dump($app['db']['event_manager']->persist($user)); -// dump( ); +// dump($dados ); return false; }); diff --git a/src/Route/ProductController.php b/src/Route/ProductController.php index b096454b..3fcac6dd 100644 --- a/src/Route/ProductController.php +++ b/src/Route/ProductController.php @@ -1,17 +1,117 @@ before(function (Request $request, Application $app) { - +$beforeProductExist = function (Request $request) use ($app) { + + $id = (int) $request->get("id"); + + $product = $app['db']->getRepository("Entity\Product")->findById($id); + + if (empty($product)) { + return new Response("Product not exists", 404); + } +}; +$productApp->before(function (Request $request) use ($app) { + //check authorization + $key = $request->headers->get('key'); + $keyDb = $app['db']->getRepository("Entity\ApiKey")->findOneByKey($key); + + if (empty($keyDb)) { + return new Response("User Unauthorized", 401); + } +}); + +$productApp->match('/', function (Request $request) use($app) { + + $dataJson = json_decode($request->getContent(), true); + $product = new Product(); + + $product->setName($dataJson['name']); + $product->setPrice($dataJson['price']); + $product->setDescription($dataJson['description']); + $product->setCategory($dataJson['category']); + + $app['db']->persist($product); + $app['db']->flush(); + + if ($product->getId() > 0) { + return new Response("Product created", 201); + } + return new Response("Product invalid", 404); +})->method('POST')->before(function (Request $request) use ($app) { + + $dataJson = json_decode($request->getContent(), true); + $product = $app['db']->getRepository("Entity\Product")->findProductByName($dataJson['name']); + + if (!empty($product)) { + return new Response("Product exists", 304); + } +}); + + +$productApp->get('/', function (Request $request) use ($app) { + + $products = $app['db']->getRepository("Entity\Product")->findAllProductsToArray(); + return $app->json($app['serializer']->serialize($products, 'json'), 200); +}); + +$productApp->get('/{id}', function ($id) use ($app) { + + $products = $app['db']->getRepository("Entity\Product")->findById($id); + return $app->json($app['serializer']->serialize($products, 'json'), 200); +})->assert('id', '\d+')->before($beforeProductExist); + + +$productApp->put('/{id}', function (Request $request, $id) use($app) { + + + $dataJson = json_decode($request->getContent(), true); + $product = $app['db']->getRepository("Entity\Product")->findById($id); + + if (isset($dataJson['name'])) { + $product->setName($dataJson['name']); + } + if (isset($dataJson['description'])) { + $product->setDescription($dataJson['description']); + } + if (isset($dataJson['price'])) { + $product->setPrice($dataJson['price']); + } + if (isset($dataJson['category'])) { + $product->setCategory($dataJson['category']); + } + + $app['db']->merge($product); + $app['db']->flush(); + + if ($product->getId() > 0) { + return new Response("Product updated", 200); + } + return new Response("Product invalid", 403); +})->assert('id', '\d+')->before($beforeProductExist); + +$productApp->delete('/{id}', function (Request $request, $id) use($app) { + + $product = $app['db']->getRepository("Entity\Product")->findById($id); + $app['db']->detach($product); + $app['db']->flush(); +})->assert('id', '\d+')->before($beforeProductExist)->after(function(Request $request) use ($app) { + + $id = (int) $request->get("id"); + + $product = $app['db']->getRepository("Entity\Product")->findById($id); + + if (empty($product)) { + return new Response("Product removed", 200); + } + return new Response("Product not removed", 304); }); -$product->get('/', function () { return 'all'; }); -$product->get('/:id', function () { return 'especific';}); -$product->post('/', function () { return 'all'; }); -$product->put('/:id', function () { return 'especific';}); -$product->delete('/:id', function () { return 'especific';}); -return $product; +return $productApp; diff --git a/src/Route/UserController.php b/src/Route/UserController.php index 534ae06c..4524aa95 100644 --- a/src/Route/UserController.php +++ b/src/Route/UserController.php @@ -1,18 +1,98 @@ before(function (Request $request, Application $app) { - -}); +$beforeUser = function (Request $request) use ($app) { + + switch ($request->getMethod()) { + case "POST": + $dataJson = json_decode($request->getContent(), true); + $result = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); + if (!empty($result)) { + return new Response("User exists", 403); + } + + break; + case "PUT": + + break; + case "DELETE": + + break; + } + +// dump($request->getMethod()); +// dump($request->getContent()); +// exit; +}; + +$beforeAutenticate = function (Request $request) use ($app) { + switch ($request->getMethod()) { + case "POST": + $dataJson = json_decode($request->getContent(), true); + $user = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); + + if (empty($user)) { + return new Response("User not exists", 403); + } + + if (!password_verify($dataJson['password'], $user->getPassword())) { + return new Response("User Unauthorized", 401); + } + + + break; + } +}; + +$userApp->match('/', function (Request $request) use ($app) { + + $dataJson = json_decode($request->getContent(), true); -$user->get('/', function () {return 'test';}); -$user->post('/', function () {return 'test';}); -$user->post('/authenticate', function () {return 'test';}); -$user->put('/:id', function () {return 'test';}); -$user->delete('/:id', function () {return 'test';}); + $user = new User(); + $user->setLogin($dataJson['login']); + $user->setPassword($dataJson['password']); + + $app['db']->persist($user); + $app['db']->flush(); + + if ($user->getId() > 0) { + return new Response("User created", 200); + } + return new Response("User invalid", 403); +})->method('POST')->before($beforeUser); + +$userApp->post('/authenticate', function (Request $request) use($app) { + //necessito de luna chave + $dataJson = json_decode($request->getContent(), true); + $user = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); + + $apiKey = new ApiKey(); + $apiKey->setUser_id($user->getId()); + $app['db']->persist($apiKey); + $app['db']->flush(); + + if ($apiKey->getId() > 0) { + return $app->json(array("key" => $apiKey->getKey()), 201); + } + return new Response("No ", 403); +})->before($beforeAutenticate); + + + + + +$userApp->put('/:id', function () { + return 'test'; +}); +$userApp->delete('/:id', function () { + return 'test'; +}); -return $user; +return $userApp; From 885afa8da1b168d39c9fe04f49ac9f186ca69b3a Mon Sep 17 00:00:00 2001 From: Osmar Queiroz Date: Fri, 5 May 2017 00:33:08 -0300 Subject: [PATCH 4/4] ajustes finais do projeto --- .gitignore | 2 +- bkp_sql.sql | 26 -------- index.php | 2 +- manual.pdf | Bin 0 -> 60896 bytes nbproject/project.properties | 8 --- nbproject/project.xml | 9 --- src/Entity/ApiKeyListener.php | 8 +-- src/Entity/Product.php | 11 ++++ src/Entity/ProductListener.php | 8 +-- src/Entity/UserListener.php | 4 +- src/Repository/UserRepository.php | 3 + src/Route/ProductController.php | 35 ++++++----- src/Route/UserController.php | 97 ++++++++++++++++++------------ 13 files changed, 103 insertions(+), 110 deletions(-) delete mode 100644 bkp_sql.sql create mode 100644 manual.pdf delete mode 100644 nbproject/project.properties delete mode 100644 nbproject/project.xml diff --git a/.gitignore b/.gitignore index 3ec25333..3d8f399d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /vendor/ -/nbproject/private/ +/nbproject/ /db/store.db diff --git a/bkp_sql.sql b/bkp_sql.sql deleted file mode 100644 index dc29cbde..00000000 --- a/bkp_sql.sql +++ /dev/null @@ -1,26 +0,0 @@ -BEGIN TRANSACTION; -CREATE TABLE "user" ( - `id` INTEGER PRIMARY KEY AUTOINCREMENT, - `login` TEXT, - `password` TEXT, - `create_at` NUMERIC, - `update_at` NUMERIC -); -CREATE TABLE `product` ( - `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - `name` TEXT NOT NULL, - `description` BLOB NOT NULL, - `price` REAL DEFAULT '0.00', - `category` TEXT, - `create_at` NUMERIC, - `update_at` NUMERIC -); -CREATE TABLE `api_key` ( - `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - `user_id` INTEGER, - `key` TEXT NOT NULL, - `create_at` NUMERIC NOT NULL, - `expire_at` NUMERIC NOT NULL, - FOREIGN KEY(user_id) REFERENCES user(id) -); -COMMIT; diff --git a/index.php b/index.php index 3b8f9b00..9535abd6 100644 --- a/index.php +++ b/index.php @@ -23,7 +23,7 @@ $app = new Silex\Application(); $app['debug'] = true; $app['db'] = $entityManager; -//$app->register(new Silex\Provider\ValidatorServiceProvider()); + $app->register(new Silex\Provider\SerializerServiceProvider()); $app->mount("/", include "src".DIRECTORY_SEPARATOR."Route".DIRECTORY_SEPARATOR."BaseController.php"); diff --git a/manual.pdf b/manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4845b31ca1ab19aba8bfb70f4a40ade2871a010b GIT binary patch literal 60896 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 MR%K;%OmzAF2mgl7SpWb4 literal 0 HcmV?d00001 diff --git a/nbproject/project.properties b/nbproject/project.properties deleted file mode 100644 index 46ccf393..00000000 --- a/nbproject/project.properties +++ /dev/null @@ -1,8 +0,0 @@ -auxiliary.org-netbeans-modules-php-doctrine2.enabled=true -include.path=${php.global.include.path} -php.version=PHP_56 -source.encoding=UTF-8 -src.dir=. -tags.asp=false -tags.short=false -web.root=. diff --git a/nbproject/project.xml b/nbproject/project.xml deleted file mode 100644 index 0bc49495..00000000 --- a/nbproject/project.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - org.netbeans.modules.php.project - - - testeapi - - - diff --git a/src/Entity/ApiKeyListener.php b/src/Entity/ApiKeyListener.php index 8806a97a..45e1238f 100644 --- a/src/Entity/ApiKeyListener.php +++ b/src/Entity/ApiKeyListener.php @@ -4,12 +4,12 @@ use Doctrine\ORM\Event\PreUpdateEventArgs; -class ApiKeyListener { +class ApiKeyListener { public function preFlush(ApiKey $apikey) { - $apikey->createKey(); - $apikey->updatedTimestamps(); - return $apikey; + $apikey->createKey(); + $apikey->updatedTimestamps(); + return $apikey; } } diff --git a/src/Entity/Product.php b/src/Entity/Product.php index 18fd7d75..4181fabb 100644 --- a/src/Entity/Product.php +++ b/src/Entity/Product.php @@ -26,6 +26,9 @@ class Product { /** @Column(type="string") */ protected $category; + /** @Column(type="decimal") */ + protected $discount; + /** * @Column(type="datetime") */ @@ -52,6 +55,10 @@ public function getPrice() { return $this->price; } + public function getDiscount() { + return $this->discount; + } + public function getCategory() { return $this->category; } @@ -80,6 +87,10 @@ public function setPrice($price) { $this->price = $price; } + public function setDiscount($discount) { + $this->discount = $discount; + } + public function setCategory($category) { $this->category = $category; } diff --git a/src/Entity/ProductListener.php b/src/Entity/ProductListener.php index 4f603687..031325c1 100644 --- a/src/Entity/ProductListener.php +++ b/src/Entity/ProductListener.php @@ -4,12 +4,12 @@ use Doctrine\ORM\Event\PreUpdateEventArgs; -class ProductListener { +class ProductListener { public function preFlush(Product $product) { - - $product->updatedTimestamps(); - return $product; + + $product->updatedTimestamps(); + return $product; } } diff --git a/src/Entity/UserListener.php b/src/Entity/UserListener.php index 224ff171..b36dd1e0 100644 --- a/src/Entity/UserListener.php +++ b/src/Entity/UserListener.php @@ -8,8 +8,8 @@ class UserListener { public function preFlush(User $user) { $password = $user->getPassword(); - if (strlen($password) < 60) { - $user->setPassword(password_hash($password,PASSWORD_DEFAULT)); + if (strlen($password) < 60) { + $user->setPassword(password_hash($password, PASSWORD_DEFAULT)); } $user->updatedTimestamps(); return $user; diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index 250173dd..67aa4994 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -14,6 +14,9 @@ public function findAllUsers() { public function findUser($login) { return $this->findOneBy(['login' => $login]); } + public function findUserById($id) { + return $this->findOneBy(['id' => $id]); + } diff --git a/src/Route/ProductController.php b/src/Route/ProductController.php index 3fcac6dd..3a74a155 100644 --- a/src/Route/ProductController.php +++ b/src/Route/ProductController.php @@ -2,22 +2,22 @@ $productApp = $app['controllers_factory']; -use Symfony\Component\Console\Application; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\JsonResponse; use Entity\Product; -$beforeProductExist = function (Request $request) use ($app) { +$checkProductExist = function (Request $request) use ($app) { $id = (int) $request->get("id"); $product = $app['db']->getRepository("Entity\Product")->findById($id); + if (empty($product)) { return new Response("Product not exists", 404); } }; + $productApp->before(function (Request $request) use ($app) { //check authorization $key = $request->headers->get('key'); @@ -26,6 +26,8 @@ if (empty($keyDb)) { return new Response("User Unauthorized", 401); } + $app['db']->merge($keyDb); + $app['db']->flush(); }); $productApp->match('/', function (Request $request) use($app) { @@ -35,6 +37,7 @@ $product->setName($dataJson['name']); $product->setPrice($dataJson['price']); + $product->setDiscount($dataJson['discount']); $product->setDescription($dataJson['description']); $product->setCategory($dataJson['category']); @@ -59,14 +62,14 @@ $productApp->get('/', function (Request $request) use ($app) { $products = $app['db']->getRepository("Entity\Product")->findAllProductsToArray(); - return $app->json($app['serializer']->serialize($products, 'json'), 200); + return $app->json($app['serializer']->normalize($products, 'json'), 200); }); $productApp->get('/{id}', function ($id) use ($app) { $products = $app['db']->getRepository("Entity\Product")->findById($id); - return $app->json($app['serializer']->serialize($products, 'json'), 200); -})->assert('id', '\d+')->before($beforeProductExist); + return $app->json($app['serializer']->normalize($products, 'json'), 200); +})->assert('id', '\d+')->before($checkProductExist); $productApp->put('/{id}', function (Request $request, $id) use($app) { @@ -81,6 +84,9 @@ if (isset($dataJson['description'])) { $product->setDescription($dataJson['description']); } + if (isset($dataJson['discount'])) { + $product->setDiscount($dataJson['discount']); + } if (isset($dataJson['price'])) { $product->setPrice($dataJson['price']); } @@ -95,23 +101,16 @@ return new Response("Product updated", 200); } return new Response("Product invalid", 403); -})->assert('id', '\d+')->before($beforeProductExist); +})->assert('id', '\d+')->before($checkProductExist); $productApp->delete('/{id}', function (Request $request, $id) use($app) { $product = $app['db']->getRepository("Entity\Product")->findById($id); - $app['db']->detach($product); + $app['db']->remove($product); $app['db']->flush(); -})->assert('id', '\d+')->before($beforeProductExist)->after(function(Request $request) use ($app) { - - $id = (int) $request->get("id"); + ; + return new Response("Product removed", 200); +})->assert('id', '\d+')->before($checkProductExist); - $product = $app['db']->getRepository("Entity\Product")->findById($id); - - if (empty($product)) { - return new Response("Product removed", 200); - } - return new Response("Product not removed", 304); -}); return $productApp; diff --git a/src/Route/UserController.php b/src/Route/UserController.php index 4524aa95..fa69a910 100644 --- a/src/Route/UserController.php +++ b/src/Route/UserController.php @@ -2,54 +2,57 @@ $userApp = $app['controllers_factory']; -use Symfony\Component\Console\Application; +use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Entity\User; use Entity\ApiKey; -$beforeUser = function (Request $request) use ($app) { +$checkUserPermisson = function (Request $request) use ($app) { + //check authorization - switch ($request->getMethod()) { - case "POST": - $dataJson = json_decode($request->getContent(), true); - $result = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); - if (!empty($result)) { - return new Response("User exists", 403); - } + $key = $request->headers->get('key'); + $keyDb = $app['db']->getRepository("Entity\ApiKey")->findOneByKey($key); - break; - case "PUT": - - break; - case "DELETE": - - break; + if (empty($keyDb)) { + return new Response("User Unauthorized", 401); } - -// dump($request->getMethod()); -// dump($request->getContent()); -// exit; }; -$beforeAutenticate = function (Request $request) use ($app) { - switch ($request->getMethod()) { - case "POST": - $dataJson = json_decode($request->getContent(), true); - $user = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); +$checkUserNotExists = function (Request $request) use ($app) { - if (empty($user)) { - return new Response("User not exists", 403); - } + if ($request->getMethod() == "POST") { + $dataJson = json_decode($request->getContent(), true); + $result = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); + if (!empty($result)) { + return new Response("User exists", 403); + } + } +}; - if (!password_verify($dataJson['password'], $user->getPassword())) { - return new Response("User Unauthorized", 401); - } +$checkUserAutenticate = function (Request $request) use ($app) { + if ($request->getMethod() == "POST") { + $dataJson = json_decode($request->getContent(), true); + $user = $app['db']->getRepository("Entity\User")->findUser($dataJson['login']); + if (empty($user)) { + return new Response("User not exists", 403); + } - break; + if (!password_verify($dataJson['password'], $user->getPassword())) { + return new Response("User Unauthorized", 401); + } } }; +$userApp->get('/', function (Request $request) use($app) { + $key = $request->headers->get('key'); + $apiKey = $app['db']->getRepository("Entity\ApiKey")->findOneByKey($key); + $user_id = $apiKey->getUser_id(); + $user = $app['db']->getRepository("Entity\User")->findUserById($user_id); + + return $app->json($app['serializer']->serialize($user, 'json'), 200); +}); + $userApp->match('/', function (Request $request) use ($app) { @@ -65,8 +68,9 @@ if ($user->getId() > 0) { return new Response("User created", 200); } + return new Response("User invalid", 403); -})->method('POST')->before($beforeUser); +})->method('POST')->before($checkUserNotExists); $userApp->post('/authenticate', function (Request $request) use($app) { //necessito de luna chave @@ -82,17 +86,36 @@ return $app->json(array("key" => $apiKey->getKey()), 201); } return new Response("No ", 403); -})->before($beforeAutenticate); +})->before($checkUserAutenticate); +$userApp->put('/', function (Request $request) use ($app) { + $key = $request->headers->get('key'); + $apiKey = $app['db']->getRepository("Entity\ApiKey")->findOneByKey($key); + $user_id = $apiKey->getUser_id(); + $user = $app['db']->getRepository("Entity\User")->findUserById($user_id); + $dataJson = json_decode($request->getContent(), true); + + if (isset($dataJson['login'])) { + $user->setLogin($dataJson['login']); + } + if (isset($dataJson['password'])) { + $user->setPassword($dataJson['password']); + } + $app['db']->merge($user); + $app['db']->flush(); + + if ($user->getId() > 0) { + return new Response("User updated", 200); + } + return new Response("USer invalid", 403); +})->before($checkUserPermisson); -$userApp->put('/:id', function () { - return 'test'; -}); $userApp->delete('/:id', function () { return 'test'; }); + return $userApp;