diff --git a/.editorconfig b/.editorconfig index 82d0fff..f8d0528 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,10 +9,10 @@ trim_trailing_whitespace = true insert_final_newline = true indent_style = space -[{app,www}/**.{php,html}] +[{app,asset}/**.{php,html}] indent_size = 4 -[www/**.{css,js}] +[asset/**.{css,js}] indent_size = 2 [*.{json,yml}] diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..fc40d74 --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +DB_DRIVER=mysql +DB_HOST=localhost +DB_USER=root +DB_PASS= +DB_NAME= + +MAIL_HOST=mailtrap.io +MAIL_PORT=2525 +MAIL_USER= +MAIL_PASS= + +CLOUDINARY_NAME= +CLOUDINARY_KEY= +CLOUDINARY_SECRET= + +GCAPTCHA_KEY= +GCAPTCHA_SECRET= diff --git a/.gitignore b/.gitignore index 29ecb1b..72870ed 100644 --- a/.gitignore +++ b/.gitignore @@ -12,13 +12,11 @@ Icon? # Development files # -------------------------- -app/settings.php .env # Dependency folders # -------------------------- /vendor -/.htaccess # IDE Project Configurations # -------------------------- @@ -30,5 +28,4 @@ nbproject/ # But Keep these # -------------------------- -!/www/.htaccess !.gitkeep diff --git a/www/.htaccess b/.htaccess similarity index 100% rename from www/.htaccess rename to .htaccess diff --git a/LISENCE.md b/LISENCE.md new file mode 100644 index 0000000..fdb9c3a --- /dev/null +++ b/LISENCE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 by PHP Indonesia + +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. diff --git a/Procfile b/Procfile index b2206a0..8da9fc2 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: vendor/bin/heroku-php-apache2 www/ +web: vendor/bin/heroku-php-apache2 . diff --git a/README.md b/README.md index 1c41d8d..f39e578 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### Kebutuhan - PHP 5.5 keatas. -- HTTP Server, misal NginX or Apache. +- HTTP Server, misal NginX atau Apache. - MySQL Server 5.x keatas untuk database utama. ### Instalasi @@ -31,7 +31,7 @@ **NOTE**: sesuaikan `[db-user]` anda, umumnya adalah `root` -4. Import kedua file `.sql` yang ada dalam folder `app/data` secara berurutan ke `[db-name]` yang telah anda buat: +4. Import kedua file `.sql` yang ada dalam folder `app/database` secara berurutan ke `[db-name]` yang telah anda buat: 1. `membership-schema.sql` 2. `membership-values.sql` @@ -39,20 +39,20 @@ Dari terminal bisa dilakukan dengan cara ```bash - $ mysql -u[db-user] -p [db-name] < app/data/membership-schema.sql app/data/membership-values.sql + $ mysql -u[db-user] -p [db-name] < app/database/membership-schema.sql app/database/membership-values.sql ``` -5. Copy-Paste file `settings.php.disable` didalam folder `app` dan rename menjadi `settings.php` lalu buka dengan editor favorit anda dan sesuaikan isi konfigurasi didalamnya, misal Sublime Text: `subl`. +5. Copy-Paste file `.env.example` didalam direktori projek dan rename menjadi `.env` lalu buka dengan editor favorit anda dan sesuaikan isi konfigurasi didalamnya, misal Sublime Text: `subl`. ``` - $ cp app/settings.php.disable app/settings.php - $ subl -a app/settings.php + $ cp .env.example .env + $ subl -a .env ``` -6. Jika anda menggunakan web server seperti Apache atau NginX, silahkan sesuaikan vhost -nya atau gunakan PHP built in server dan arahkan ke folder `www` sebagai docroot. +6. Jika anda menggunakan web server seperti Apache atau NginX, silahkan sesuaikan vhost -nya atau gunakan PHP built in server dan arahkan project root sebagai docroot. ``` - $ php -S localhost:8088 -t www/ + $ php -S localhost:8088 ``` 7. Terakhir, buka url sesuai dengan konfigurasi lokal server anda. Misal [`http://localhost:8088/`](http://localhost:8088/). @@ -61,11 +61,10 @@ | Path | Keterangan | | --- | --- | -| `app/` | Direktori utama aplikasi | -| `app/data/` | Direktori database | -| `app/src/` | Direktori source code aplikasi | +| `app/` | Berisi source code utama aplikasi | +| `app/database/` | Berisi file database `*.sql` | | `app/views/` | Direktori template | -| `www/` | Direktori public | +| `assets/` | Asset directori | ### Cara berkontribusi: diff --git a/app.json b/app.json new file mode 100644 index 0000000..1d3c3b8 --- /dev/null +++ b/app.json @@ -0,0 +1,10 @@ +{ + "name": "PHP.id Membership Reloaded", + "repository": "https://github.com/phpindonesia/phpindonesia.or.id-membership2", + "image": "heroku/php", + "scripts": { + "postdeploy": "echo deployed; return 0;", + "pr-predestroy": "echo destroyng; return 0;" + }, + "env": {} +} diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..b5d0a33 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,2 @@ +Options -Indexes +deny from all diff --git a/app/bootstrap.php b/app/bootstrap.php deleted file mode 100644 index 3e854ca..0000000 --- a/app/bootstrap.php +++ /dev/null @@ -1,21 +0,0 @@ -load(); + /** * Slim Container * - * @var \Slim\Container $container + * @var Container $container */ $container = new Container([ 'settings' => require $settingsFile ]); +/** + * Application setting. + * + * @param Container $container + * @return callable + */ +$container['setting'] = function ($container) { + /** + * @param string $name + * @param mixed $default + * @return array|string + */ + return function ($name, $default = null) use ($container) { + $settings = $container->get('settings'); + + return array_key_exists($name, $settings) ? $settings[$name] : $default; + }; +}; + +/** + * Custom error handler + * + * TODO: need more!!! + * + * @param Container $container + * @return callable + */ +$container['errorHandler'] = function ($container) { + if ($container->get('settings')['mode'] !== 'development') { + /** + * @param \Slim\Http\Request $request + * @param \Slim\Http\Response $response + * @param \Exception $exception + */ + return function ($request, $response, $exception) use ($container) { + return $container->get('view')->render('error::500', [ + 'message' => $exception->getMessage() + ])->withStatus(500); + }; + } + + return new SlimError(true); +}; + /** * Setup session * @@ -44,43 +98,31 @@ * Setup database container * * @param Container $container - * @return Database + * @return Membership\Database */ $container['db'] = function ($container) { - $db = $container->get('settings')['db']; - if (!isset($db['dsn'])) { - $db['dsn'] = sprintf('%s:host=%s;dbname=%s', $db['driver'], $db['host'], $db['dbname']); + $settings = $container->get('settings')->get('db'); + + if (!isset($settings['dsn'])) { + $settings['dsn'] = sprintf( + '%s:host=%s;dbname=%s', + $settings['driver'], + $settings['host'], + $settings['dbname'] + ); } - return new Database($db['dsn'], $db['username'], $db['password']); + return new Membership\Database($settings['dsn'], $settings['username'], $settings['password']); }; /** - * Setup data model container + * Setup validator container * - * @param Container $container * @return callable */ -$container['data'] = function ($container) { - $db = $container->get('db'); - $session = $container->get('session'); - - return function ($class) use ($db, $session) { - if (!class_exists($class)) { - throw new LogicException("Data model class {$class} not exists "); - } - - $model = new ReflectionClass($class); - - if (!$model->isSubclassOf(Models::class)) { - throw new InvalidArgumentException(sprintf( - 'Data model must be instance of %s, %s given', - Models::class, - $model->getName() - )); - } - - return $model->newInstance($db, $session); +$container[Validator::class] = function () { + return function (\Slim\Http\Request $request) { + return new Validator($request->getParams(), [], 'id'); }; }; @@ -91,9 +133,9 @@ * @return \Valitron\Validator */ $container['validator'] = function ($container) { - $request = $container->get('request'); - $viewData = $container->get('view')->getPlates()->getData('sections::captcha'); - $validator = new Validator($request->getParams(), [], 'id'); + $instance = $container->get(Validator::class); + $validator = $instance($container->get('request')->getParams()); + $viewData = $container->get('view')->getPlates()->getData('section::captcha'); if ($viewData['gcaptchaEnable'] == true) { $remoteAddr = $container->get('environment')->get('REMOTE_ADDR'); @@ -122,6 +164,29 @@ return new Slim\Flash\Messages; }; +/** + * This service MUST return a SHARED instance + * of \Slim\Interfaces\InvocationStrategyInterface. + * + * @return \Slim\Interfaces\InvocationStrategyInterface + */ +$container['foundHandler'] = function () { + return new \Membership\Http\ActionResolver(); +}; + +/** + * PSR-7 Request object + * + * @param Container $container + * + * @return \Membership\Http\Request + */ +$container['request'] = function ($container) { + $request = \Membership\Http\Request::createFromEnvironment($container->get('environment')); + + return $request->setValidator($container->get(Validator::class)); +}; + /** * Setup cloudinary config before view */ @@ -136,18 +201,18 @@ $container['view'] = function ($container) { $settings = $container->get('settings'); $view = new Projek\Slim\Plates( - $viewSettings = $settings->get('view'), - $container->get('response') + $viewSettings = $settings->get('view') ); // Add app view folders - $view->addFolder('emails', $viewSettings['directory'].'/emails'); - $view->addFolder('layouts', $viewSettings['directory'].'/layouts'); - $view->addFolder('sections', $viewSettings['directory'].'/sections'); + $view->addFolder('email', $viewSettings['directory'].DIRECTORY_SEPARATOR.'_emails'); + $view->addFolder('error', $viewSettings['directory'].DIRECTORY_SEPARATOR.'_errors'); + $view->addFolder('layout', $viewSettings['directory'].DIRECTORY_SEPARATOR.'_layouts'); + $view->addFolder('section', $viewSettings['directory'].DIRECTORY_SEPARATOR.'_sections'); // Load app view extensions - $view->loadExtension(new PlatesAsset(WWW_DIR)); - $view->loadExtension(new Libraries\ViewExtension( + $view->loadExtension(new PlatesAsset(ROOT_DIR)); + $view->loadExtension(new Membership\ViewExtension( $request = $container->get('request'), $container->get('flash'), $settings->get('mode') @@ -157,6 +222,34 @@ return $view; }; +/** + * PSR-7 Response object + * + * @param Container $container + * + * @return \Membership\Http\Response + */ +$container['response'] = function ($container) { + $headers = new \Slim\Http\Headers(['Content-Type' => 'text/html; charset=UTF-8']); + $response = new \Membership\Http\Response(200, $headers); + + return $response->setView($container->get('view')) + ->setRouter($container->get('router')) + ->withProtocolVersion($container->get('settings')['httpVersion']); +}; + +/** + * Setup upload handler container + * + * @return \Http\Client\Curl\Client + */ +$container['httpClient'] = function () { + return new \Http\Client\Curl\Client( + new \Http\Message\MessageFactory\SlimMessageFactory(), + new \Http\Message\StreamFactory\SlimStreamFactory() + ); +}; + /** * Setup upload handler container * @@ -212,48 +305,67 @@ }; /** - * Setup smtp mailer container + * Setup SparkPost mailer + * + * @param Container $container + * @return \Membership\Mail\SparkpostMessage + */ +$container[\Membership\Mail\SparkpostMessage::class] = function ($container) { + $options = [ + CURLOPT_SSL_VERIFYPEER => false, // Stop cURL from verifying the peer's certificate + CURLOPT_SSL_VERIFYSTATUS => false, // Stop cURL from verifying the peer's certificate + ]; + + return new \Membership\Mail\SparkpostMessage( + $container->get('httpClient'), + $container->get('settings')['sparkpost']['api_key'], + $options + ); +}; + +/** + * Setup SMTP mailer * * @param Container $container - * @return Libraries\Mailer + * @return \Membership\Mail\SmtpMessage */ -$container['mailer'] = function ($container) { +$container[\Membership\Mail\SmtpMessage::class] = function ($container) { + $mailer = new \PHPMailer(true); + $settings = $container->get('settings')->get('mail'); - $view = $container->get('view')->getPlates(); - $settings = $container->get('settings'); - $appSetting = $settings->get('app'); + $mailer->Host = $settings['host']; + $mailer->Port = $settings['port']; + $mailer->Username = $settings['username']; + $mailer->Password = $settings['password']; - $mailer = new Libraries\Mailer($settings->get('mailer'), $view); + $mailer->isSMTP(); - $mailer->debugMode($settings->get('mode')); - $mailer->setSender($appSetting['email'], $appSetting['name']); + $mailer->SMTPAuth = $settings['auth']; + $mailer->SMTPSecure = $settings['secure']; - return $mailer; + return new \Membership\Mail\SmtpMessage($mailer); }; /** - * Custom error handler - * - * TODO: need more!!! + * Setup mailer container * * @param Container $container - * @return callable + * @return Membership\Mail */ -$container['errorHandler'] = function ($container) { - if ($container->get('settings')['mode'] !== 'development') { - /** - * @param \Slim\Http\Request $request - * @param \Slim\Http\Response $response - * @param \Exception $exception - */ - return function ($request, $response, $exception) use ($container) { - return $container->get('view')->render('errors/500', [ - 'message' => $exception->getMessage() - ])->withStatus(500); - }; +$container['mail'] = function ($container) { + $settings = $container->get('settings'); + $drivers = [ + 'smtp' => \Membership\Mail\SmtpMessage::class, + 'sparkpost' => \Membership\Mail\SparkpostMessage::class, + ]; + + if (! array_key_exists($settings['mail']['driver'], $drivers)) { + throw new InvalidArgumentException('No mail driver found'); } - return new SlimError(true); + $driver = $settings['mail']['driver']; + + return new Membership\Mail($container->get($drivers[$driver]), $container->get('view'), $settings['app']); }; return $container; diff --git a/app/data/membership-schema.sql b/app/database/membership-schema.sql similarity index 100% rename from app/data/membership-schema.sql rename to app/database/membership-schema.sql diff --git a/app/data/membership-values.sql b/app/database/membership-values.sql similarity index 98% rename from app/data/membership-values.sql rename to app/database/membership-values.sql index d1a5980..fb32b29 100644 --- a/app/data/membership-values.sql +++ b/app/database/membership-values.sql @@ -1,5 +1,5 @@ -- --- Dumping data for table `career_levels` +-- Dumping database for table `career_levels` -- INSERT INTO `career_levels` (`career_level_id`, `order_by`) VALUES @@ -13,7 +13,7 @@ INSERT INTO `career_levels` (`career_level_id`, `order_by`) VALUES ('VOLUNTEER', 1); -- --- Dumping data for table `industries` +-- Dumping database for table `industries` -- INSERT INTO `industries` (`industry_id`, `industry_name`) VALUES @@ -84,7 +84,7 @@ INSERT INTO `industries` (`industry_id`, `industry_name`) VALUES (65, 'General & Wholesale Trading'); -- --- Dumping data for table `jobs` +-- Dumping database for table `jobs` -- INSERT INTO `jobs` (`job_id`) VALUES @@ -95,7 +95,7 @@ INSERT INTO `jobs` (`job_id`) VALUES ('PELAJAR'); -- --- Dumping data for table `regionals` +-- Dumping database for table `regionals` -- INSERT INTO `regionals` (`id`, `regional_name`, `parent_id`, `province_code`, `city_code`) VALUES @@ -649,7 +649,7 @@ INSERT INTO `regionals` (`id`, `regional_name`, `parent_id`, `province_code`, `c (553, 'KAB. DEIYAI', 467, '94', '36'); -- --- Dumping data for table `religions` +-- Dumping database for table `religions` -- INSERT INTO `religions` (`religion_id`, `religion_name`) VALUES @@ -661,7 +661,7 @@ INSERT INTO `religions` (`religion_id`, `religion_name`) VALUES (6, 'Others'); -- --- Dumping data for table `roles` +-- Dumping database for table `roles` -- INSERT INTO `roles` (`role_id`, `title_alias`, `deleted`) VALUES @@ -671,7 +671,7 @@ INSERT INTO `roles` (`role_id`, `title_alias`, `deleted`) VALUES ('volunteer', 'Author Voluntary', 'N'); -- --- Dumping data for table `skills` +-- Dumping database for table `skills` -- INSERT INTO `skills` (`skill_id`, `parent_id`, `skill_name`, `created`, `modified`, `deleted`) VALUES diff --git a/app/routes.php b/app/routes.php index cb1f6ee..40ca516 100644 --- a/app/routes.php +++ b/app/routes.php @@ -1,12 +1,7 @@ get('/', HomeController::class.':index')->setName('membership-index'); +$app->get('/', Controllers\HomeController::class.':index')->setName('membership-index'); // Login end-point -$app->get('/login', HomeController::class.':loginPage')->setName('membership-login'); -$app->post('/login', HomeController::class.':login'); +$app->get('/login', Controllers\HomeController::class.':loginPage')->setName('membership-login'); +$app->post('/login', Controllers\HomeController::class.':login'); // Registration end-point -$app->get('/register', HomeController::class.':registerPage')->setName('membership-register'); -$app->post('/register', HomeController::class.':register'); +$app->get('/register', Controllers\HomeController::class.':registerPage')->setName('membership-register'); +$app->post('/register', Controllers\HomeController::class.':register'); // Logout end-point -$app->get('/logout', HomeController::class.':logout')->setName('membership-logout'); +$app->get('/logout', Controllers\HomeController::class.':logout')->setName('membership-logout'); // Forgot password end-point -$app->get('/forgot-password', PasswordController::class.':forgotPage')->setName('membership-forgot-password'); -$app->post('/forgot-password', PasswordController::class.':forgot'); +$app->get('/forgot-password', Controllers\PasswordController::class.':forgotPage')->setName('membership-forgot-password'); +$app->post('/forgot-password', Controllers\PasswordController::class.':forgot'); // Reset password end-point -$app->get('/reset-password/{uid:[0-9]+}/{reset_key}', PasswordController::class.':reset')->setName('membership-reset-password'); +$app->get('/reset-password/{user_id:[0-9]+}/{reset_key}', Controllers\PasswordController::class.':reset')->setName('membership-reset-password'); // Account activation end-point -$app->get('/activate/{uid:[0-9]+}/{activation_key}', AccountController::class.':activate')->setName('membership-activation'); +$app->get('/activate/{user_id:[0-9]+}/{activation_key}', Controllers\AccountController::class.':activate')->setName('membership-activation'); // Account reactivation end-point // TODO: need tobe done -$app->get('/reactivate', AccountController::class.':reactivatePage')->setName('membership-account-reactivate'); -$app->post('/reactivate', AccountController::class.':reactivate'); +$app->get('/reactivate', Controllers\AccountController::class.':reactivatePage')->setName('membership-account-reactivate'); +$app->post('/reactivate', Controllers\AccountController::class.':reactivate'); // Javascript? -$app->get('/javascript', AccountController::class.':javascriptPage')->setName('membership-account-javascript'); +$app->get('/javascript', Controllers\AccountController::class.':javascriptPage')->setName('membership-account-javascript'); $app->group('/account', function () { // Account home - $this->get('[/]', AccountController::class.':index')->setName('membership-account'); + $this->get('[/]', Controllers\AccountController::class.':index')->setName('membership-account'); // Edit account - $this->get('/edit', AccountController::class.':editPage')->setName('membership-account-edit'); - $this->put('/edit', AccountController::class.':edit')->setName('membership-account-update'); + $this->get('/edit', Controllers\AccountController::class.':editPage')->setName('membership-account-edit'); + $this->put('/edit', Controllers\AccountController::class.':edit')->setName('membership-account-update'); // Update account password - $this->get('/update-password', PasswordController::class.':updatePage')->setName('membership-account-password-edit'); - $this->put('/update-password', PasswordController::class.':update')->setName('membership-account-password-update'); + $this->get('/update-password', Controllers\PasswordController::class.':updatePage')->setName('membership-account-password-edit'); + $this->put('/update-password', Controllers\PasswordController::class.':update')->setName('membership-account-password-update'); // Delete account? - $this->delete('/{id:[0-9]+}', AccountController::class.':delete')->setName('membership-account-delete'); + $this->delete('/{id:[0-9]+}', Controllers\AccountController::class.':delete')->setName('membership-account-delete'); // Account portfolios $this->group('/portfolio', function () { // View and Update Portfolio - $this->get('/{id:[0-9]+}', PortfoliosController::class.':index')->setName('membership-portfolios-edit'); - $this->put('/{id:[0-9]+}', PortfoliosController::class.':edit')->setName('membership-portfolios-update'); + $this->get('/{id:[0-9]+}', Controllers\PortfoliosController::class.':index')->setName('membership-portfolios-edit'); + $this->put('/{id:[0-9]+}', Controllers\PortfoliosController::class.':edit')->setName('membership-portfolios-update'); // Delete Portfolio - $this->delete('/{id:[0-9]+}', PortfoliosController::class.':delete')->setName('membership-portfolios-delete'); + $this->delete('/{id:[0-9]+}', Controllers\PortfoliosController::class.':delete')->setName('membership-portfolios-delete'); // Create new Portfolio - $this->get('/add', PortfoliosController::class.':addPage')->setName('membership-portfolios-add'); - $this->post('/', PortfoliosController::class.':add')->setName('membership-portfolios-create'); + $this->get('/add', Controllers\PortfoliosController::class.':addPage')->setName('membership-portfolios-add'); + $this->post('/', Controllers\PortfoliosController::class.':add')->setName('membership-portfolios-create'); })->add(Middleware::class.':authorizePorfolioRoute'); @@ -86,15 +81,15 @@ $this->group('/skills', function () { // View and Update skill - $this->get('/{id:[0-9]+}', SkillsController::class.':index')->setName('membership-skills-edit'); - $this->put('/{id:[0-9]+}', SkillsController::class.':edit')->setName('membership-skills-update'); + $this->get('/{id:[0-9]+}', Controllers\SkillsController::class.':index')->setName('membership-skills-edit'); + $this->put('/{id:[0-9]+}', Controllers\SkillsController::class.':edit')->setName('membership-skills-update'); // Delete skill - $this->delete('/{id:[0-9]+}', SkillsController::class.':delete')->setName('membership-skills-delete'); + $this->delete('/{id:[0-9]+}', Controllers\SkillsController::class.':delete')->setName('membership-skills-delete'); // Create new skill - $this->get('/add', SkillsController::class.':addPage')->setName('membership-skills-add'); - $this->post('/', SkillsController::class.':add')->setName('membership-skills-create'); + $this->get('/add', Controllers\SkillsController::class.':addPage')->setName('membership-skills-add'); + $this->post('/', Controllers\SkillsController::class.':add')->setName('membership-skills-create'); })->add(Middleware::class.':authorizeSkillRoute'); @@ -103,8 +98,8 @@ // Regionals end-point $app->group('/regionals', function () { - $this->get('/provinces', RegionalsController::class.':provinces')->setName('regionals-provinces'); - $this->get('/cities/{province_id:[0-9]+}', RegionalsController::class.':cities')->setName('regionals-cities'); + $this->get('/provinces', Controllers\RegionalsController::class.':provinces')->setName('regionals-provinces'); + $this->get('/cities/{province_id:[0-9]+}', Controllers\RegionalsController::class.':cities')->setName('regionals-cities'); }); @@ -112,5 +107,5 @@ * TODO: normalize username, * - Username should accept alphanumeric, dash and underscore only [A-z\d\-\_] */ -$app->get('/{username}', AccountController::class.':profile')->setName('membership-profile'); +$app->get('/{username}', Controllers\AccountController::class.':profile')->setName('membership-profile'); diff --git a/app/settings.php b/app/settings.php new file mode 100644 index 0000000..c5ffed1 --- /dev/null +++ b/app/settings.php @@ -0,0 +1,62 @@ + 'development', + + 'salt_pwd' => 'dev-spirit', + + 'app' => [ + 'name' => 'PHP Indonesia - Membership App', + 'email' => 'admin@membership.phpindonesia.id', + 'url' => 'membership.phpindonesia.id', + 'home_url' => 'phpindonesia.id' + ], + + 'db' => [ + 'driver' => env('DB_DRIVER', 'mysql'), + 'host' => env('DB_HOST', 'localhost'), + 'username' => env('DB_USER', 'root'), + 'password' => env('DB_PASS'), + 'dbname' => env('DB_NAME'), + ], + + 'mail' => [ + 'driver' => env('MAIL_DRIVER', $mail_url['scheme']), + 'host' => env('MAIL_HOST', $mail_url['host']), + 'port' => env('MAIL_PORT', $mail_url['port']), + 'username' => env('MAIL_USER', $mail_url['user']), + 'password' => env('MAIL_PASS', $mail_url['pass']), + ], + + 'gcaptcha' => [ + 'enable' => true, + 'sitekey' => env('GCAPTCHA_KEY'), + 'secret' => env('GCAPTCHA_SECRET') + ], + + 'cloudinary' => [ + 'cloud_name' => env('CLOUDINARY_NAME'), + 'api_key' => env('CLOUDINARY_KEY'), + 'api_secret' => env('CLOUDINARY_SECRET'), + ], + + 'sparkpost' => [ + 'api_key' => env('SPARKPOST_API_KEY') + ], + + 'view' => [ + 'directory' => APP_DIR.'views', + 'fileExtension' => 'php', + ], + + 'socmedias' => [ + 'facebook' => ['Facebook', 'fa-facebook', 'http://facebook.com/'], + 'twitter' => ['Twitter', 'fa-twitter', 'http://twitter.com/'], + 'linkedin' => ['LinkedIn', 'fa-linkedin', 'http://linkedin.com/in/'], + 'instagram' => ['Instagram', 'fa-instagram', 'http://instagram.com/'], + 'path' => ['Path', 'fa-pinterest-p', 'http://path.com/'], + 'github' => ['GitHub', 'fa-github', 'http://github.com/'], + ], +]; diff --git a/app/settings.php.disable b/app/settings.php.disable deleted file mode 100644 index 16fe122..0000000 --- a/app/settings.php.disable +++ /dev/null @@ -1,44 +0,0 @@ - 'development', - 'salt_pwd' => 'dev-spirit', - 'app' => [ - 'name' => 'PHP Indonesia - Membership App', - 'email' => '', - ], - 'db' => [ - 'host' => 'localhost', - 'driver' => 'mysql', - 'username' => 'root', - 'password' => '', - 'dbname' => '', - ], - 'mailer' => [ - 'host' => 'smtp.gmail.com', - 'port' => 586, - 'username' => '', - 'password' => '', - ], - 'view' => [ - 'directory' => APP_DIR.'views', - 'fileExtension' => 'php', - ], - 'gcaptcha' => [ - 'enable' => true, - 'sitekey' => '6LfJzg4TAAAAANipQttg0q0TL6VJJCPgDdBcnAR7', - 'secret' => '6LfJzg4TAAAAAE2Vwoy39WAulllaK4wV_O_0H-kf' - ], - 'cloudinary' => [ - 'cloud_name' => '', - 'api_key' => '', - 'api_secret' => '', - ], - 'socmedias' => [ - 'facebook' => ['Facebook', 'fa-facebook', 'https://www.facebook.com/'], - 'twitter' => ['Twitter', 'fa-twitter', 'https://twitter.com/'], - 'linkedin' => ['LinkedIn', 'fa-linkedin', 'https://www.linkedin.com/in/'], - 'instagram' => ['Instagram', 'fa-instagram', 'https://www.instagram.com/'], - 'path' => ['Path', 'fa-pinterest-p', 'https://path.com/'], - 'github' => ['GitHub', 'fa-github', 'https://github.com/'], - ], -]; diff --git a/app/src/Collection.php b/app/src/Collection.php new file mode 100644 index 0000000..40e17f4 --- /dev/null +++ b/app/src/Collection.php @@ -0,0 +1,33 @@ +has($key)) { + $data[$key] = $this->get($key); + } + } + + return new static($data); + } + + public function values() + { + return array_values($this->data); + } + + public function filter($callable = null, $flag = 0) + { + return array_filter($this->data, $callable, $flag); + } +} diff --git a/app/src/ContainerAware.php b/app/src/ContainerAware.php index 3ece7bf..8b5d07c 100644 --- a/app/src/ContainerAware.php +++ b/app/src/ContainerAware.php @@ -1,20 +1,21 @@ setPageTitle('Membership', 'Profil Anggota'); - - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - - if ($request->isXhr()) { - $outputJson = $this->normalizeUserJsonOutput($users); - - return $response->withJson($outputJson); - } - - return $this->view->render('account-index', [ - 'member' => $users->getProfile(), - 'member_portfolios' => $users->getPortfolios(), - 'member_skills' => $users->getSkills(), - 'member_socmeds' => $users->getSocmends(), - 'socmedias' => $this->settings->get('socmedias'), - ]); - } - - public function profile(Request $request, Response $response, array $args) - { - $this->setPageTitle('Membership', 'Detail Anggota'); - - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - $user = $users->getProfileUsername($args['username']); - - if (!$user) { - throw new NotFoundException($request, $response); - } - - if ($request->isXhr()) { - $outputJson = [ - 'username' => $user['username'], - 'fullname' => $user['fullname'], - 'email' => $user['email'], - 'gender' => $user['gender'], - 'city' => $user['city'], - 'province' => $user['province'], - ]; - - return $response->withJson($outputJson); - } - - return $this->view->render('profile-index', [ - 'member' => $user, - 'member_portfolios' => $users->getPortfolios($user['user_id']), - 'member_skills' => $users->getSkills($user['user_id']), - 'member_socmeds' => $users->getSocmends($user['user_id']), - 'socmedias' => $this->settings->get('socmedias'), - ]); - } - - public function editPage(Request $request, Response $response, array $args) - { - $this->setPageTitle('Membership', 'Update Profile Anggota'); - - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - /** @var \Membership\Models\Regionals $regionals */ - $regionals = $this->data(Models\Regionals::class); - /** @var \Membership\Models\Religions $religion */ - $religions = $this->data(Models\Religions::class); - $provinceId = $users->getProfile()['province_id']; - - return $this->view->render('account-edit', [ - 'member' => $users->getProfile(), - 'member_socmeds' => $users->getSocmends(), - 'religions' => array_pairs($religions->get()->fetchAll(), 'religion_id', 'religion_name'), - 'provinces' => array_pairs($regionals->getProvinces(), 'id', 'regional_name'), - 'cities' => array_pairs($regionals->getCities($provinceId), 'id', 'regional_name'), - 'jobs' => array_pairs($this->data(Models\Careers::class)->getJobs(), 'job_id'), - 'genders' => ['female' => 'Wanita', 'male' => 'Pria'], - 'identity_types' => ['ktp' => 'KTP', 'sim' => 'SIM', 'ktm' => 'Kartu Mahasiswa'], - 'socmedias' => $this->settings->get('socmedias'), - ]); - } - - public function edit(Request $request, Response $response, array $args) - { - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - $user = $users->get(['email', 'username'], $this->session->get('user_id'))->fetch(); - $identityTypes = ['ktp' => 'KTP', 'sim' => 'SIM', 'ktm' => 'Kartu Mahasiswa']; - $validator = $this->validator->rule('required', [ - 'email', - 'username', - 'fullname', - 'province_id', - 'city_id', - 'area', - 'job_id', - ]); - - $validator->addRule('assertEmailNotExists', function ($field, $value, array $params) use ($users, $user) { - return $user['email'] == $value || !$users->assertEmailExists($value); - }, 'tersebut sudah terdaftar!'); - - $validator->addRule('assertUsernameNotExists', function ($field, $value, array $params) use ($users, $user) { - $protected = [ - 'admin', - 'account', 'login', 'register', 'logout', - 'activate', 'reactivate', 'regionals', - 'forgot-password', 'reset-password' - ]; - return $user['username'] == $value || (!in_array($value, $protected) && !$users->assertUsernameExists($value)); - }, 'tersebut sudah terdaftar!'); - - $validator->rules([ - 'regex' => [ - ['fullname', ':^[A-z\s]+$:'], - ['username', ':^[A-z\d\-\.\_]+$:'], - ['contact_phone', ':^[-\+\d]+$:'], - ['identity_number', ':^[^\W_]+$:'], - ], - 'email' => 'email', - 'assertEmailNotExists' => 'email', - 'assertUsernameNotExists' => 'username', - 'dateFormat' => [ - ['birth_date', 'Y-m-d'] - ], - 'equals' => [ - ['repassword', 'password'] - ], - 'in' => [ - ['identity_type', array_keys($identityTypes)] - ], - 'lengthMax' => [ - ['fullname', 32], - ['username', 64], - ['contact_phone', 16], - ['area', 64], - ['identity_number', 32], - ['birth_place', 32], - ], - 'lengthMin' => [ - ['username', 6], - ['password', 6], - ], - ]); - - if ($validator->validate()) { - $input = $request->getParsedBody(); - /** @var \Membership\Models\MemberProfile $profile */ - $profile = $this->data(Models\MemberProfile::class); - /** @var \Membership\Models\MemberSocmeds $socmeds */ - $socmeds = $this->data(Models\MemberSocmeds::class); - - $memberProfile = [ - 'fullname' => $input['fullname'], - 'contact_phone' => $input['contact_phone'], - 'birth_place' => strtoupper($input['birth_place']), - 'birth_date' => $input['birth_date'], - 'identity_number' => $input['identity_number'], - 'identity_type' => $input['identity_type'], - 'religion_id' => $input['religion_id'], - 'province_id' => $input['province_id'], - 'city_id' => $input['city_id'], - 'area' => $input['area'], - 'job_id' => $input['job_id'] - ]; - - $this->db->beginTransaction(); - - try { - $userId = $this->session->get('user_id'); - - if ($photo = $request->getUploadedFiles()['photo']) { - $memberProfile = $this->upload($photo, $memberProfile); - } - - // Update profile data record - $profile->update($memberProfile, ['user_id' => $userId]); - - $users->update([ - 'email' => $input['email'], - 'username' => $input['username'], - 'province_id' => $input['province_id'], - 'city_id' => $input['city_id'], - 'area' => $input['area'], - ], ['user_id' => $userId]); - - // Handle social medias - if ($input['socmeds']) { - $terms = [ - 'user_id' => $userId, - 'deleted' => 'N', - ]; - - foreach ($input['socmeds'] as $item) { - $terms = [ - 'user_id' => $userId, - 'deleted' => 'N', - 'socmed_type' => $item['socmed_type'], - ]; - - $socmedRow = $socmeds->get(['account_name', 'account_url'], $terms)->fetch(); - - if ($socmedRow) { - if ($socmedRow['account_name'] != $item['account_name']) { - $socmedRow['account_name'] = $item['account_name']; - } - - if ($socmedRow['account_url'] != $item['account_url']) { - $socmedRow['account_url'] = $item['account_url']; - } - - $socmeds->update($socmedRow, $terms); - } else { - - $termsStatus = [ - 'user_id' => $userId, - 'socmed_type' => $item['socmed_type'], - 'deleted' => 'Y', - ]; - - $socmedAdd = [ - 'user_id' => $userId, - 'socmed_type' => $item['socmed_type'], - 'account_name' => $item['account_name'], - 'account_url' => $item['account_url'], - ]; - - $socmedId = $socmeds->get(['member_socmed_id'], $termsStatus)->fetch(); - - if ($socmedId) { - $socmedAdd['deleted'] = 'N'; - $socmeds->update($socmedAdd, $termsStatus); - } else { - $socmeds->create($socmedAdd); - } - } - } - } - - if (isset($input['socmeds_delete'])) { - foreach ($input['socmeds_delete'] as $item) { - $terms = [ - 'user_id' => $userId, - 'deleted' => 'N', - 'socmed_type' => $item, - ]; - - $socmedRow = $socmeds->get(['user_id'], $terms)->fetch(); - - if ($socmedRow) { - $socmeds->delete([ - 'user_id' => $userId, - 'socmed_type' => $item - ]); - } - } - } - - $this->db->commit(); - - $this->addFormAlert('success', 'Profile information successfuly updated! Congratulation!'); - } catch (\PDOException $e) { - $this->db->rollback(); - - $this->addFormAlert('error', 'System failed
'.$e->getMessage()); - } catch (\Exception $e) { - $this->db->rollback(); - - $this->addFormAlert('error', 'System failed
'.$e->getMessage()); - } - } else { - $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - - return $response->withRedirect($this->router->pathFor('membership-account-edit', $args)); - } - - return $response->withRedirect($this->router->pathFor('membership-account')); - } - - public function activate(Request $request, Response $response, array $args) - { - /** @var \Membership\Models\Users $users */ - $activation = $this->data(Models\UsersActivations::class); - - if ($activation->isExists($args['uid'], $args['activation_key']) && - $activation->activate($args['uid'], $args['activation_key']) - ) { - $this->addFormAlert('success', 'Selamat! Account anda sudah aktif. Silahkan login...'); - } else { - $this->addFormAlert('error', 'Bad Request'); - } - - return $response->withRedirect($this->router->pathFor('membership-login')); - } - - public function reactivatePage(Request $request, Response $response, array $args) - { - $this->enableCaptcha(); - $this->setPageTitle('Membership', 'Account Reactivation'); - - $this->view->addData([ - 'helpTitle' => 'Bantuan Login?', - 'helpContent' => [ - 'Jika belum terdaftar sebagai anggota, Daftar Disini menjadi anggota PHP Indonesia.', - 'Sudah pernah terdaftar menjadi anggota PHP Indonesia, silahkan Login Disini.' - ], - ], 'layouts::account'); - - return $this->view->render('account-reactivate'); - } - - public function reactivate(Request $request, Response $response, array $args) - { - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - $validator = $this->validator->rule('required', 'email'); - - $validator->addRule('assertNotEmailExists', function ($field, $value, array $params) use ($users) { - return !$users->assertEmailExists($value); - }, 'Email tersebut tidak terdaftar!'); - - $validator->rule('assertNotEmailExists', 'email'); - - if ($validator->validate()) { - // - $this->addFormAlert('error', 'Bad Request'); - } else { - $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - - return $response->withRedirect($this->router->pathFor('membership-login')); - } - - return $response->withRedirect($this->router->pathFor('membership-account-reactivate')); - } - - public function javascript(Request $request, Response $response, array $args) - { - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - $cookie = $request->getCookieParams(); - $open_portfolio = false; - $open_skill = false; - $worker = ['KARYAWAN', 'FREELANCER', 'OWNER', 'MAHASISWA-KARYAWAN']; - $student = ['PELAJAR', 'MAHASISWA']; - - if (in_array($this->session->get('job_id'), $worker)) { - if (!isset($cookie['portfolio-popup'])) { - $open_portfolio = $users->countPortfolios() === 0; - } - - if (!isset($cookie['skill-popup'])) { - $open_skill = $users->countSkills() === 0; - } - } elseif (in_array($this->session->get('job_id'), $student)) { - if (!isset($cookie['skill-popup'])) { - $open_skill = $users->countSkills() === 0; - } - } - - return $this->view->render('account-javascript', [ - 'open_portfolio' => $open_portfolio, - 'open_skill' => $open_skill - ])->withHeader('Content-Type', 'application/javascript'); - } - - public function portfolioCookie(Request $request, Response $response, array $args) - { - $cookie = $request->getCookieParams(); - if (!isset($cookie['portfolio-popup'])) { - setcookie('portfolio-popup', 1, $this->cookieTtl()); - } - - return $response->withJson(['resp' => 'OK']); - } - - public function skillsCookie(Request $request, Response $response, array $args) - { - $cookie = $request->getCookieParams(); - if (!isset($cookie['skill-popup'])) { - setcookie('skill-popup', 1, $this->cookieTtl()); - } - - return $response->withJson(['resp' => 'OK']); - } - - private function cookieTtl() - { - return time() + 86400; - } - - private function normalizeUserJsonOutput(Users $users, $userId = null) - { - $user = $users->getProfile($userId); - - $output = [ - 'id' => $user['user_id'], - 'username' => $user['username'], - 'email' => $user['email'], - 'fullname' => $user['fullname'], - 'phone' => $user['contact_phone'], - 'photo' => $user['photo'], - 'birthPlace' => $user['birth_place'], - 'birthDate' => $user['birth_date'], - 'identityType' => $user['identity_type'], - 'identityNumber' => $user['identity_number'], - 'gender' => $user['gender'], - 'religion' => $user['religion_name'], - 'area' => $user['area'], - 'city' => $user['city'], - 'province' => $user['province'], - 'portfolios' => [], - 'skills' => [], - 'socmeds' => [], - ]; - - foreach ($users->getPortfolios($user['user_id']) as $i => $portfolio) { - $output['portfolios'][$i] = [ - 'id' => $portfolio['member_portfolio_id'], - 'companyName' => $portfolio['company_name'], - 'industryName' => $portfolio['industry_name'], - 'workStatus' => $portfolio['work_status'], - 'jobTitle' => $portfolio['job_title'], - 'jobDesc' => $portfolio['job_desc'], - ]; - } - - foreach ($users->getSkills($user['user_id']) as $i => $skill) { - $output['skills'][$i] = [ - 'id' => $skill['member_skill_id'], - 'name' => $skill['skill_name'], - 'parent' => $skill['skill_parent_name'], - 'assesment' => $skill['skill_self_assesment'], - ]; - } - - foreach ($users->getSocmends($user['user_id']) as $i => $socmend) { - $output['socmeds'][$i] = [ - 'type' => $socmend['socmed_type'], - 'name' => $socmend['account_name'], - 'url' => $socmend['account_url'], - ]; - } - - return $output; - } -} diff --git a/app/src/Controllers/HomeController.php b/app/src/Controllers/HomeController.php deleted file mode 100644 index 86c6a48..0000000 --- a/app/src/Controllers/HomeController.php +++ /dev/null @@ -1,240 +0,0 @@ -setPageTitle('Membership', 'Keanggotaan'); - - /** @var Models\Regionals $regionals */ - $regionals = $this->data(Models\Regionals::class); - $provinceId = $request->getQueryParam('province_id'); - - /** @var Models\Users $users */ - $users = $this->data(Models\Users::class); - - return $this->view->render('home-index', [ - 'members' => $users->getMembers($request), - 'totalMember' => $users->getTotalMember($request), - 'provinces' => array_pairs($regionals->getProvinces(), 'id', 'regional_name'), - 'cities' => array_pairs($regionals->getCities($provinceId), 'id', 'regional_name'), - ]); - } - - public function loginPage(Request $request, Response $response, array $args) - { - $this->setPageTitle('Membership', 'Login Anggota'); - - $this->view->addData([ - 'helpTitle' => 'Bantuan Login?', - 'helpContent' => [ - 'Jika belum terdaftar sebagai anggota, Daftar Disini menjadi anggota PHP Indonesia.', - 'Hilang atau lupa password login, silahkan Reset Password Anda.' - ], - ], 'layouts::account'); - - return $this->view->render('home-login'); - } - - public function login(Request $request, Response $response, array $args) - { - /** @var Models\Users $users */ - $users = $this->data(Models\Users::class); - $input = $request->getParsedBody(); - $validator = $this->validator->rule('required', ['login', 'password']); - - if (filter_var($input['login'], FILTER_VALIDATE_EMAIL)) { - $validator->rule('email', [$input['login']]); - } - - if (!$validator->validate()) { - $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - - return $response->withRedirect($this->router->pathFor('membership-login')); - } - - try { - $user = $users->authenticate($input['login'], $this->salt($input['password'])); - } catch (\InvalidArgumentException $e) { - $this->addFormAlert('error', $e->getMessage()); - - return $response->withRedirect($this->router->pathFor('membership-login')); - } - - if ($user) { - $_SESSION['MembershipAuth'] = [ - 'user_id' => $user['user_id'] - ]; - $this->session->replace($_SESSION['MembershipAuth']); - - $users->updateLogin($user['user_id']); - } - - return $response->withRedirect($this->router->pathFor('membership-account')); - } - - public function registerPage(Request $request, Response $response, array $args) - { - $this->enableCaptcha(); - $this->setPageTitle('Membership', 'Registrasi Anggota'); - - $this->view->addData([ - 'helpTitle' => 'Bantuan Register?', - 'helpContent' => [ - 'Sudah pernah terdaftar menjadi anggota PHP Indonesia, silahkan Login Disini', - 'Hilang atau lupa password login, silahkan Reset Password Anda.' - ], - ], 'layouts::account'); - - /** @var Models\Regionals $regionals */ - $regionals = $this->data(Models\Regionals::class); - $provinceId = $request->getParam('province_id'); - - return $this->view->render('home-register', [ - 'provinces' => array_pairs($regionals->getProvinces(), 'id', 'regional_name'), - 'cities' => array_pairs($regionals->getCities($provinceId), 'id', 'regional_name'), - 'jobs' => array_pairs($this->data(Models\Careers::class)->getJobs(), 'job_id'), - ]); - } - - public function register(Request $request, Response $response, array $args) - { - /** @var Models\Users $users */ - $users = $this->data(Models\Users::class); - $input = $request->getParsedBody(); - $validator = $this->validator->rule('required', [ - 'email', 'username', 'fullname', 'password', 'repassword', - 'job_id', 'gender_id', 'province_id', 'area', - // 'city_id', // disable it for now - ]); - - $validator->addRule('assertEmailNotExists', function ($field, $value, array $params) use ($users) { - return !$users->assertEmailExists($value); - }, 'tersebut sudah terdaftar! Silahkan gunakan email lain'); - - $validator->addRule('assertUsernameNotExists', function ($field, $value, array $params) use ($users) { - $protected = [ - 'admin', - 'account', 'login', 'register', 'logout', - 'activate', 'reactivate', 'regionals', - 'forgot-password', 'reset-password' - ]; - return !in_array($value, $protected) && !$users->assertUsernameExists($value); - }, 'tersebut sudah terdaftar! Silahkan gunakan username lain'); - - $validator->rules([ - 'regex' => [ - ['fullname', ':^[A-z\s]+$:'], - ['username', ':^[A-z\d\-\_]+$:'], - ], - 'email' => 'email', - 'assertEmailNotExists' => 'email', - 'assertUsernameNotExists' => 'username', - 'dateFormat' => [ - ['birth_date', 'Y-m-d'] - ], - 'equals' => [ - ['repassword', 'password'] - ], - 'notIn' => [ - ['username', 'password'] - ], - 'lengthMax' => [ - ['username', 32], - ['fullname', 64], - ['area', 64], - ], - 'lengthMin' => [ - ['username', 6], - ['password', 6], - ], - ]); - - if ($validator->validate()) { - $emailAddress = $input['email']; - $activationKey = md5(uniqid(rand(), true)); - $activationExpiredDate = date('Y-m-d H:i:s', time() + 172800); // 48 jam - $registerSuccessMsg = 'Haayy '.$input['fullname'].',
Submission keanggotan sudah berhasil disimpan. Akan tetapi account anda tidak langsung aktif. Demi keamanan dan validitas data, maka sistem telah mengirimkan email ke email anda, untuk melakukan aktivasi account. Segera check email anda! Terimakasih ^_^'; - - try { - $input['activation_key'] = $activationKey; - $input['expired_date'] = $activationExpiredDate; - $input['fullname'] = ucwords($input['fullname']); - $input['password'] = $this->salt($input['password']); - - $userId = $users->create($input); - } catch (\PDOException $e) { - $this->addFormAlert('error', 'System failed
'.$e->getMessage()); - - return $response->withRedirect($this->router->pathFor('membership-register')); - } - - if ($userId) { - try { - $mail = $this->mailer->to($emailAddress, $input['fullname']) - ->withSubject('PHP Indonesia - Aktivasi Membership') - ->withBody('emails::activation', [ - 'email' => $emailAddress, - 'fullname' => $input['fullname'], - 'regDate' => date('d-m-Y H:i:s'), - 'activationExp' => $activationExpiredDate, - 'activationUrl' => $request->getUri()->getBaseUrl().$this->router->pathFor('membership-activation', ['uid' => $userId, 'activation_key' => $activationKey]), - ]); - - $mail->send(); - } catch (\phpmailerException $e) { - if ($this->settings['mode'] = 'development') { - throw $e; - } - - $mailSend = false; - $registerSuccessMsg .= '

Kemungkinan email akan sampai agak terlambat, karena email server kami sedang mengalami sedikit kendala teknis. Jika anda belum juga mendapatkan email, maka jangan ragu untuk laporkan kepada kami melalu email: report@phpindonesia.or.id'; - } - - if ($mailSend) { - // Update email sent status - $this->data(Models\UsersActivations::class)->update(['email_sent' => 'Y'], [ - 'user_id' => $userId, - 'activation_key' => $activationKey - ]); - } - } - - $this->addFormAlert('success', $registerSuccessMsg); - } else { - $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - - return $response->withRedirect($this->router->pathFor('membership-register')); - } - - return $response->withRedirect($this->router->pathFor('membership-index')); - } - - public function logout(Request $request, Response $response, array $args) - { - $_SESSION = []; - - if (ini_get('session.use_cookies')) { - $params = session_get_cookie_params(); - setcookie( - session_name(), - '', - time() - 42000, - $params["path"], - $params["domain"], - $params["secure"], - $params["httponly"] - ); - } - - session_destroy(); - - return $response->withRedirect($this->router->pathFor('membership-login')); - } -} diff --git a/app/src/Database.php b/app/src/Database.php new file mode 100644 index 0000000..883edfd --- /dev/null +++ b/app/src/Database.php @@ -0,0 +1,42 @@ +beginTransaction(); + + try { + $callback(); + + return $this->commit(); + } catch (\PDOException $e) { + $this->rollBack(); + + throw $e; + } catch (\Throwable $e) { + throw $e; + } + } +} diff --git a/app/src/Libraries/PDO/SelectStatement.php b/app/src/Database/SelectStatement.php similarity index 76% rename from app/src/Libraries/PDO/SelectStatement.php rename to app/src/Database/SelectStatement.php index 2f016d5..5530c4c 100644 --- a/app/src/Libraries/PDO/SelectStatement.php +++ b/app/src/Database/SelectStatement.php @@ -1,10 +1,8 @@ setValues($column->values); - } - else - { + } else { $this->values[] = $value; } @@ -48,8 +43,6 @@ public function where($column, $operator = null, $value = null, $chainType = 'AN */ public function combine() { - $stmt = new StatementCombination($this->dbh); - - return $stmt; + return new StatementCombination($this->dbh); } } diff --git a/app/src/Libraries/PDO/StatementCombination.php b/app/src/Database/StatementCombination.php similarity index 71% rename from app/src/Libraries/PDO/StatementCombination.php rename to app/src/Database/StatementCombination.php index cca6e1e..ae4619d 100644 --- a/app/src/Libraries/PDO/StatementCombination.php +++ b/app/src/Database/StatementCombination.php @@ -1,13 +1,12 @@ container[] = $column instanceof StatementCombination + ? ' '.$chainType.' '.$column + : ' '.$chainType.' '.$column.' '.$operator.' ?'; + } +} diff --git a/app/src/Http/ActionResolver.php b/app/src/Http/ActionResolver.php new file mode 100644 index 0000000..c7c5b9d --- /dev/null +++ b/app/src/Http/ActionResolver.php @@ -0,0 +1,69 @@ + $v) { + $request = $request->withAttribute($k, $v); + } + + foreach ($reflection->getParameters() as $parameter) { + if ($class = $parameter->getClass()) { + $interfaces = $class->getInterfaceNames(); + + if (in_array(ServerRequestInterface::class, $interfaces)) { + $args[] = $request; + } elseif (in_array(ResponseInterface::class, $interfaces)) { + $args[] = $response; + } else { + $interfaces[] = $class->getName(); + + foreach ($interfaces as $interface) { + if ($this->container->has($interface)) { + $args[] = $this->container->get($interface); + } + } + } + } elseif ($parameter->getName() === 'args') { + $args[] = $routeArguments; + } elseif (isset($routeArguments[$parameter->getName()])) { + $args[] = $routeArguments[$parameter->getName()]; + } elseif ($this->container->has($parameter->getName())) { + $args[] = $this->container->get($parameter->getName()); + } + } + + return $reflection->invokeArgs($instance, $args); + } + + public function withContainer(Container $container) + { + $this->container = $container; + } +} diff --git a/app/src/Controllers.php b/app/src/Http/Controllers.php similarity index 82% rename from app/src/Controllers.php rename to app/src/Http/Controllers.php index ad3ee45..d220441 100644 --- a/app/src/Controllers.php +++ b/app/src/Http/Controllers.php @@ -1,11 +1,11 @@ null, 'gcaptchaSecret' => null, 'gcaptchaEnable' => false, - ], 'sections::captcha'); + ], 'section::captcha'); $this->view->addData([ 'session' => $session->all(), @@ -42,9 +42,9 @@ public function __construct(Container $container) /** * Assert is XHR request * - * @param \Slim\Http\Request $request - * @param \Slim\Http\Response $response - * @throws \Slim\Exception\NotFoundException + * @param Request $request + * @param Response $response + * @throws NotFoundException */ protected function assertXhrRequest(Request $request, Response $response) { @@ -56,8 +56,8 @@ protected function assertXhrRequest(Request $request, Response $response) /** * Assert is HTML request * - * @param \Slim\Http\Request $request - * @param \Slim\Http\Response $response + * @param Request $request + * @param Response $response * @throws \Slim\Exception\NotFoundException */ protected function assertHTMLRequest(Request $request, Response $response) @@ -78,7 +78,7 @@ protected function setPageTitle($mainTitle = '', $subTitle = '') $this->view->addData([ 'page_title' => $mainTitle, 'sub_page_title' => $subTitle, - ], 'layouts::system'); + ], 'layout::system'); } /** @@ -89,7 +89,7 @@ protected function setPageTitle($mainTitle = '', $subTitle = '') protected function flashValidationErrors(array $errors) { foreach ($errors as $field => $message) { - $this->flash->addMessage('validation.errors.'.$field, implode(', ', $message)); + $this->flash->addMessage('validation._errors.'.$field, implode(', ', $message)); } if ($inputs = $this->request->getParsedBody()) { @@ -101,7 +101,7 @@ protected function flashValidationErrors(array $errors) * Add Form alert * * @param string $type - * @param array $message + * @param string $message * @param array $errors */ protected function addFormAlert($type, $message, array $errors = []) @@ -118,10 +118,10 @@ protected function addFormAlert($type, $message, array $errors = []) $this->view->addData([ 'formAlert' => ['type' => $type, 'message' => $message] - ], 'sections::alert'); + ], 'section::alert'); foreach ($errors as $field => $error) { - $this->flash->addMessage('validation.errors.'.$field, implode(', ', $error)); + $this->flash->addMessage('validation._errors.'.$field, implode(', ', $error)); } if ($inputs = $this->request->getParsedBody()) { @@ -141,7 +141,7 @@ protected function enableCaptcha() 'gcaptchaEnable' => $settings['enable'], 'gcaptchaSitekey' => $settings['sitekey'], 'gcaptchaSecret' => $settings['secret'], - ], 'sections::captcha'); + ], 'section::captcha'); return $settings; } @@ -165,14 +165,11 @@ protected function salt($password) */ protected function setHeaderLogin() { - /** @var Users $users */ - $users = $this->data(Users::class); - - $profile = $users->getProfile(); + $profile = (new Users())->getProfile(); $this->view->addData([ 'header_photo' => $profile['photo'], 'header_username' => $profile['username'], - ], 'sections::header'); + ], 'section::header'); } } diff --git a/app/src/Http/Controllers/AccountController.php b/app/src/Http/Controllers/AccountController.php new file mode 100644 index 0000000..ea6d42d --- /dev/null +++ b/app/src/Http/Controllers/AccountController.php @@ -0,0 +1,351 @@ +setPageTitle('Membership', 'Profil Anggota'); + + $users = new Models\Users; + + if ($request->isXhr()) { + return $response->withJson( + $this->normalizeUserJsonOutput($users) + ); + } + + return $response->view('account-index', [ + 'member' => $users->getProfile(), + 'member_portfolios' => $users->getPortfolios(), + 'member_skills' => $users->getSkills(), + 'member_socmeds' => $users->getSocmends(), + 'socmedias' => $this->settings->get('socmedias'), + ]); + } + + public function profile(Request $request, Response $response, $username) + { + $this->setPageTitle('Membership', 'Detail Anggota'); + + $users = new Models\Users; + + if (! $user = $users->getProfileUsername($username)) { + throw new NotFoundException($request, $response); + } + + if ($request->isXhr()) { + return $response->withJson([ + 'username' => $user['username'], + 'fullname' => $user['fullname'], + 'email' => $user['email'], + 'gender' => $user['gender'], + 'city' => $user['city'], + 'province' => $user['province'], + ]); + } + + return $response->view('profile-index', [ + 'member' => $user, + 'member_portfolios' => $users->getPortfolios($user['user_id']), + 'member_skills' => $users->getSkills($user['user_id']), + 'member_socmeds' => $users->getSocmends($user['user_id']), + 'socmedias' => $this->settings->get('socmedias'), + ]); + } + + public function editPage(Response $response) + { + $this->setPageTitle('Membership', 'Update Profile Anggota'); + + $users = new Models\Users; + $regionals = new Models\Regionals; + $religions = new Models\Religions; + $provinceId = $users->getProfile()['province_id']; + + return $response->view('account-edit', [ + 'member' => $users->getProfile(), + 'member_socmeds' => $users->getSocmends(), + 'religions' => array_pairs($religions->get()->fetchAll(), 'religion_id', 'religion_name'), + 'provinces' => array_pairs($regionals->getProvinces(), 'id', 'regional_name'), + 'cities' => array_pairs($regionals->getCities($provinceId), 'id', 'regional_name'), + 'jobs' => array_pairs((new Models\Careers)->getJobs(), 'job_id'), + 'genders' => Models\Users::GENDERS, + 'identity_types' => Models\Users::IDENTITY_TYPES, + 'socmedias' => $this->settings->get('socmedias'), + ]); + } + + public function edit(Request $request, Response $response, array $args) + { + $request->rules('required', ['email', 'username', 'fullname', 'province_id', 'city_id', 'area', 'job_id']); + + try { + $request->validate(new Models\Users, function (Collection $input, Models\Users $users) use ($request) { + $this->db->transaction(function () use ($request, $users, $input) { + $userId = $this->session->get('user_id'); + + $users->update([ + 'email' => $input['email'], + 'username' => $input['username'], + 'province_id' => $input['province_id'], + 'city_id' => $input['city_id'], + 'area' => $input['area'], + ], ['user_id' => $userId]); + + $memberProfile = [ + 'fullname' => $input['fullname'], + 'contact_phone' => $input['contact_phone'], + 'birth_place' => $input['birth_place'], + 'birth_date' => $input['birth_date'], + 'identity_number' => $input['identity_number'], + 'identity_type' => $input['identity_type'], + 'religion_id' => $input['religion_id'], + 'province_id' => $input['province_id'], + 'city_id' => $input['city_id'], + 'area' => $input['area'], + 'job_id' => $input['job_id'] + ]; + + if ($photo = $request->getUploadedFiles()['photo']) { + $memberProfile = $this->upload($photo, $memberProfile); + } + + // Update profile database record + (new Models\MemberProfile)->update($memberProfile, ['user_id' => $userId]); + + $socmeds = new Models\MemberSocmeds; + + // Handle social medias + if ($input['socmeds']) { + $terms = ['user_id' => $userId, 'deleted' => 'N']; + + foreach ($input['socmeds'] as $item) { + $terms['socmed_type'] = $item['socmed_type']; + + if ($socmedRow = $socmeds->get(['account_name', 'account_url'], $terms)->fetch()) { + if ($socmedRow['account_name'] != $item['account_name']) { + $socmedRow['account_name'] = $item['account_name']; + } + + if ($socmedRow['account_url'] != $item['account_url']) { + $socmedRow['account_url'] = $item['account_url']; + } + + $socmeds->update($socmedRow, $terms); + } else { + $terms['deleted'] = 'Y'; + + $socmedAdd = [ + 'user_id' => $userId, + 'socmed_type' => $item['socmed_type'], + 'account_name' => $item['account_name'], + 'account_url' => $item['account_url'], + ]; + + $socmedId = $socmeds->get(['member_socmed_id'], $terms)->fetch(); + + if ($socmedId) { + $socmedAdd['deleted'] = 'N'; + $socmeds->update($socmedAdd, $terms); + } else { + $socmeds->create($socmedAdd); + } + } + } + } + + if (isset($input['socmeds_delete'])) { + foreach ($input['socmeds_delete'] as $item) { + $socmeds->delete(['user_id' => $userId, 'socmed_type' => $item]); + } + } + }); + }); + + return $response->withRedirectRoute('membership-account'); + } catch (\Throwable $e) { + if ($e instanceof ValidatorException) { + $this->addFormAlert('warning', $e->getMessage(), $e->getErrors()); + } + + $this->addFormAlert('error', 'System failed
'.$e->getMessage()); + + return $response->withRedirectRoute('membership-account-edit', $args); + } + } + + public function activate(Response $response, $uid, $activation_key) + { + $activation = new Models\UsersActivations; + + if ($activation->isExists($uid, $activation_key) && + $activation->activate($uid, $activation_key) + ) { + $this->addFormAlert('success', 'Selamat! Account anda sudah aktif. Silahkan login...'); + } else { + $this->addFormAlert('error', 'Bad Request'); + } + + return $response->withRedirectRoute('membership-login'); + } + + public function reactivatePage(Response $response) + { + $this->enableCaptcha(); + $this->setPageTitle('Membership', 'Account Reactivation'); + + $this->view->addData([ + 'helpTitle' => 'Bantuan Login?', + 'helpContent' => [ + 'Jika belum terdaftar sebagai anggota, Daftar Disini menjadi anggota PHP Indonesia.', + 'Sudah pernah terdaftar menjadi anggota PHP Indonesia, silahkan Login Disini.' + ], + ], 'layout::account'); + + return $response->view('account-reactivate'); + } + + public function reactivate(Request $request, Response $response, $user_id, $activation_key) + { + $request->rules([ + 'required' => [['email']], + 'notExists' => [['email']], + ]); + + try { + $request->validate(new Models\Users, function (Collection $input, Models\Users $users) use ($user_id, $activation_key) { + $users->activate($user_id, $activation_key); + }); + + $this->addFormAlert('error', 'Bad Request'); + + return $response->withRedirectRoute('membership-account-reactivate'); + } catch (\Throwable $e) { + if ($e instanceof ValidatorException) { + $this->addFormAlert('warning', $e->getMessage(), $e->getErrors()); + } + + $this->addFormAlert('error', 'System failed
'.$e->getMessage()); + + return $response->withRedirectRoute('membership-login'); + } + } + + public function javascript(Request $request, Response $response, array $args) + { + $users = new Models\Users; + $cookie = $request->getCookieParams(); + $open_portfolio = false; + $open_skill = false; + + if (in_array($this->session->get('job_id'), Models\Careers::WORKER_TYPES)) { + if (!isset($cookie['portfolio-popup'])) { + $open_portfolio = $users->countPortfolios() === 0; + } + + if (!isset($cookie['skill-popup'])) { + $open_skill = $users->countSkills() === 0; + } + } elseif (in_array($this->session->get('job_id'), Models\Careers::STUDENT_TYPES)) { + if (!isset($cookie['skill-popup'])) { + $open_skill = $users->countSkills() === 0; + } + } + + return $response->view('account-javascript', [ + 'open_portfolio' => $open_portfolio, + 'open_skill' => $open_skill + ])->withHeader('Content-Type', 'application/javascript'); + } + + public function portfolioCookie(Request $request, Response $response, array $args) + { + $cookie = $request->getCookieParams(); + if (!isset($cookie['portfolio-popup'])) { + setcookie('portfolio-popup', 1, $this->cookieTtl()); + } + + return $response->withJson(['resp' => 'OK']); + } + + public function skillsCookie(Request $request, Response $response, array $args) + { + $cookie = $request->getCookieParams(); + if (!isset($cookie['skill-popup'])) { + setcookie('skill-popup', 1, $this->cookieTtl()); + } + + return $response->withJson(['resp' => 'OK']); + } + + private function cookieTtl() + { + return time() + 86400; + } + + private function normalizeUserJsonOutput(Models\Users $users, $userId = null) + { + $user = $users->getProfile($userId); + + $output = [ + 'id' => $user['user_id'], + 'username' => $user['username'], + 'email' => $user['email'], + 'fullname' => $user['fullname'], + 'phone' => $user['contact_phone'], + 'photo' => $user['photo'], + 'birthPlace' => $user['birth_place'], + 'birthDate' => $user['birth_date'], + 'identityType' => $user['identity_type'], + 'identityNumber' => $user['identity_number'], + 'gender' => $user['gender'], + 'religion' => $user['religion_name'], + 'area' => $user['area'], + 'city' => $user['city'], + 'province' => $user['province'], + 'portfolios' => [], + 'skills' => [], + 'socmeds' => [], + ]; + + foreach ($users->getPortfolios($user['user_id']) as $i => $portfolio) { + $output['portfolios'][$i] = [ + 'id' => $portfolio['member_portfolio_id'], + 'companyName' => $portfolio['company_name'], + 'industryName' => $portfolio['industry_name'], + 'workStatus' => $portfolio['work_status'], + 'jobTitle' => $portfolio['job_title'], + 'jobDesc' => $portfolio['job_desc'], + ]; + } + + foreach ($users->getSkills($user['user_id']) as $i => $skill) { + $output['skills'][$i] = [ + 'id' => $skill['member_skill_id'], + 'name' => $skill['skill_name'], + 'parent' => $skill['skill_parent_name'], + 'assesment' => $skill['skill_self_assesment'], + ]; + } + + foreach ($users->getSocmends($user['user_id']) as $i => $socmend) { + $output['socmeds'][$i] = [ + 'type' => $socmend['socmed_type'], + 'name' => $socmend['account_name'], + 'url' => $socmend['account_url'], + ]; + } + + return $output; + } +} diff --git a/app/src/Http/Controllers/HomeController.php b/app/src/Http/Controllers/HomeController.php new file mode 100644 index 0000000..79fed15 --- /dev/null +++ b/app/src/Http/Controllers/HomeController.php @@ -0,0 +1,183 @@ +setPageTitle('Membership', 'Keanggotaan'); + + $users = new Models\Users; + $regionals = new Models\Regionals; + + $provinceId = $request->getQueryParam('province_id'); + + return $response->view('home-index', [ + 'members' => $users->getMembers($request), + 'totalMember' => $users->getTotalMember($request), + 'provinces' => array_pairs($regionals->getProvinces(), 'id', 'regional_name'), + 'cities' => array_pairs($regionals->getCities($provinceId), 'id', 'regional_name'), + ]); + } + + public function loginPage(Response $response) + { + $this->setPageTitle('Membership', 'Login Anggota'); + + $this->view->addData([ + 'helpTitle' => 'Bantuan Login?', + 'helpContent' => [ + 'Jika belum terdaftar sebagai anggota,
Daftar Disini menjadi anggota PHP Indonesia.', + 'Hilang atau lupa password login, silahkan Reset Password Anda.' + ], + ], 'layout::account'); + + return $response->view('home-login'); + } + + public function login(Request $request, Response $response) + { + $request->rules([ + 'required' => ['login', 'password'] + ]); + + try { + $request->validate(new Models\Users, function (Collection $input, Models\Users $users) { + $user = $users->authenticate( + $input->get('login'), + $this->salt($input->get('password')) + ); + + if ($user) { + $_SESSION['MembershipAuth'] = [ + 'user_id' => $user['user_id'] + ]; + $this->session->replace($_SESSION['MembershipAuth']); + + $users->updateLogin($user['user_id']); + } + }); + + return $response->withRedirectRoute('membership-account'); + } catch (\Throwable $e) { + if ($e instanceof ValidatorException) { + $this->addFormAlert('warning', $e->getMessage(), $e->getErrors()); + } + + $this->addFormAlert('error', $e->getMessage()); + + $response->withRedirectRoute('membership-login'); + } + } + + public function registerPage(Request $request, Response $response) + { + $this->enableCaptcha(); + $this->setPageTitle('Membership', 'Registrasi Anggota'); + + $this->view->addData([ + 'helpTitle' => 'Bantuan Register?', + 'helpContent' => [ + 'Sudah pernah terdaftar menjadi anggota PHP Indonesia, silahkan Login Disini', + 'Hilang atau lupa password login, silahkan Reset Password Anda.' + ], + ], 'layout::account'); + + $regionals = new Models\Regionals; + $provinceId = $request->getParam('province_id'); + + return $response->view('home-register', [ + 'provinces' => array_pairs($regionals->getProvinces(), 'id', 'regional_name'), + 'cities' => array_pairs($regionals->getCities($provinceId), 'id', 'regional_name'), + 'jobs' => array_pairs((new Models\Careers)->getJobs(), 'job_id'), + ]); + } + + public function register(Request $request, Response $response) + { + $request->rules('required', [ + 'email', 'username', 'fullname', 'password', 'repassword', + 'job_id', 'gender_id', 'province_id', 'area', + // 'city_id', // disable it for now + ]); + + try { + $request->validate(new Models\Users, function (Collection $input, Models\Users $model) { + $activationKey = md5(uniqid(rand(), true)); + $activationExpiredDate = date('Y-m-d H:i:s', time() + 172800); // 48 jam + $registerSuccessMsg = 'Haayy '.$input['fullname'].',
Submission keanggotan sudah berhasil disimpan. Akan tetapi account anda tidak langsung aktif. Demi keamanan dan validitas database, maka sistem telah mengirimkan email ke email anda, untuk melakukan aktivasi account. Segera check email anda! Terimakasih ^_^'; + + $input['activation_key'] = $activationKey; + $input['expired_date'] = $activationExpiredDate; + $input['fullname'] = ucwords($input['fullname']); + $input['password'] = $this->salt($input['password']); + + if ($userId = $model->create($input)) { + $address = $input->get('email'); + $data = [ + 'user_id' => $userId, + 'activation_key' => $activationKey + ]; + + $this->mail + ->to($address, $input['fullname']) + ->subject('PHP Indonesia - Aktivasi Membership') + ->send('email::activation', [ + 'email' => $address, + 'fullname' => $input['fullname'], + 'regDate' => date('d-m-Y H:i:s'), + 'activationExp' => $activationExpiredDate, + 'activationUrl' => $this->router->pathFor('membership-activation', $data), + ]); + + // Update email sent status + (new Models\UsersActivations)->update(['email_sent' => 'Y'], $data); + + $this->addFormAlert('success', $registerSuccessMsg); + } + }); + + return $response->withRedirectRoute('membership-index'); + } catch (\Exception $e) { + if ($e instanceof ValidatorException) { + $this->addFormAlert('warning', $e->getMessage(), $e->getErrors()); + } + + $this->addFormAlert('error', 'System failed
'.$e->getMessage()); + + return $response->withRedirectRoute('membership-register'); + } + } + + public function logout(Request $request, Response $response) + { + $_SESSION = []; + + if (ini_get('session.use_cookies')) { + $params = session_get_cookie_params(); + setcookie( + session_name(), + '', + time() - 42000, + $params["path"], + $params["domain"], + $params["secure"], + $params["httponly"] + ); + } + + session_destroy(); + + $response->withRedirectRoute('membership-login'); + } +} diff --git a/app/src/Controllers/PasswordController.php b/app/src/Http/Controllers/PasswordController.php similarity index 66% rename from app/src/Controllers/PasswordController.php rename to app/src/Http/Controllers/PasswordController.php index 3ca39c3..601155a 100644 --- a/app/src/Controllers/PasswordController.php +++ b/app/src/Http/Controllers/PasswordController.php @@ -1,14 +1,16 @@ enableCaptcha(); $this->setPageTitle('Membership', 'Forgot Password'); @@ -19,15 +21,14 @@ public function forgotPage(Request $request, Response $response, array $args) 'Jika belum terdaftar sebagai anggota, Daftar Disini menjadi anggota PHP Indonesia.', 'Sudah pernah terdaftar menjadi anggota PHP Indonesia, silahkan Login Disini.' ], - ], 'layouts::account'); + ], 'layout::account'); - return $this->view->render('password-forgot'); + return $response->view('password-forgot'); } - public function forgot(Request $request, Response $response, array $args) + public function forgot(Request $request, Response $response) { - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); + $users = new Models\Users; $input = $request->getParsedBody(); $validator = $this->validator->rule('required', 'email'); $validator->rule('email', 'email'); @@ -53,7 +54,7 @@ function ($query) use ($emailAddress) { } )->fetch(); - $doReset = $this->data(Models\UsersResetPwd::class)->create([ + $doReset = (new Models\UsersResetPwd)->create([ 'user_id' => $member['user_id'], 'reset_key' => $resetKey, 'expired_date' => $resetExpiredDate, @@ -64,18 +65,18 @@ function ($query) use ($emailAddress) { $successMsg = 'Email konfirmasi lupa password sudah berhasil dikirim. Segera check email anda'; try { - $mail = $this->mailer->to($emailAddress, $member['fullname']) - ->withSubject('PHP Indonesia - Konfirmasi lupa password') - ->withBody('emails::forgot-password', [ + $data = ['uid' => $member['user_id'], 'reset_key' => $resetKey]; + + $this->mail->to($emailAddress, $member['fullname']) + ->subject('PHP Indonesia - Konfirmasi lupa password') + ->send('email::forgot-password', [ 'email' => $emailAddress, 'fullname' => $member['fullname'], 'reqDate' => date('d-m-Y H:i:s'), 'resetExp' => $resetExpiredDate, - 'resetUrl' => $request->getUri()->getBaseUrl().$this->router->pathFor('membership-reset-password', ['uid' => $member['user_id'], 'reset_key' => $resetKey]), + 'resetUrl' => $this->router->pathFor('membership-reset-password', $data), ]); - - $mail->send(); - } catch (\phpmailerException $e) { + } catch (MessageException $e) { if ($this->settings['mode'] = 'development') { throw $e; } @@ -88,24 +89,23 @@ function ($query) use ($emailAddress) { } else { $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - return $response->withRedirect($this->router->pathFor('membership-forgot-password')); + return $response->withRedirectRoute('membership-forgot-password'); } - return $response->withRedirect($this->router->pathFor('membership-login')); + $response->withRedirectRoute('membership-login'); } - public function updatePage(Request $request, Response $response, array $args) + public function updatePage(Response $response) { $this->enableCaptcha(); $this->setPageTitle('Membership', 'Update Password'); - return $this->view->render('password-update'); + return $response->view('password-update'); } - public function update(Request $request, Response $response, array $args) + public function update(Request $request, Response $response) { - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); + $users = new Models\Users; $saltPass = $this->settings->get('salt_pwd'); $password = $request->getParsedBodyParam('password'); $validator = $this->validator->rule('required', [ @@ -137,7 +137,7 @@ public function update(Request $request, Response $response, array $args) if (!$validator->validate()) { $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - return $response->withRedirect($this->router->pathFor('membership-account-password-edit')); + return $response->withRedirectRoute('membership-account-password-edit'); } $users->update( @@ -147,58 +147,55 @@ public function update(Request $request, Response $response, array $args) $this->addFormAlert('success', 'Password anda berhasil diubah! Selamat!'); - return $response->withRedirect($this->router->pathFor('membership-account')); + return $response->withRedirectRoute('membership-account'); } - public function reset(Request $request, Response $response, array $args) + public function reset(Request $request, Response $response, $uid, $reset_key) { - /** @var \Membership\Models\Users $users */ - $users = $this->data(Models\Users::class); - /** @var \Membership\Models\UsersResetPwd $usersResetPass */ - $usersResetPass = $this->data(Models\UsersResetPwd::class); + $users = new Models\Users; + $usersResetPass = (new Models\UsersResetPwd); - if ($usersResetPass->verifyUserKey($args['uid'], $args['reset_key'])) { + if ($usersResetPass->verifyUserKey($uid, $reset_key)) { // Create temporary password $tmpPass = substr(str_shuffle(md5(microtime())), 0, 10); $users->update([ 'password' => $this->salt($tmpPass), 'modified_by' => 0 - ], (int) $args['uid']); + ], (int) $uid); $usersResetPass->delete([ - 'user_id' => (int) $args['uid'], - 'reset_key' => $args['reset_key'] + 'user_id' => (int) $uid, + 'reset_key' => $reset_key ]); // Fetch member basic info $member = $users->get( ['u.user_id', 'u.username', 'u.email', 'm.fullname'], - function ($query) use ($args) { + function ($query) use ($uid) { $query->from('users u') ->leftJoin('members_profiles m', 'u.user_id', '=', 'm.user_id') - ->where('u.user_id', '=', (int) $args['uid']) + ->where('u.user_id', '=', (int) $uid) ->where('u.deleted', '=', 'N'); } )->fetch(); try { - $mail = $this->mailer->to($member['email'], $member['fullname']) - ->withSubject('PHP Indonesia - Password baru sementara') - ->withBody('emails::reset-password', [ + $this->mail + ->to($member['email'], $member['fullname']) + ->subject('PHP Indonesia - Password baru sementara') + ->send('email::reset-password', [ 'tmpPass' => $tmpPass, 'fullname' => $member['fullname'], ]); - $mail->send(); - $successMsg = 'Password baru sementara anda sudah dikirim ke email, Segera check email anda.'; - } catch (\phpmailerException $e) { + } catch (MessageException $e) { if ($this->settings['mode'] = 'development') { throw $e; } - $successMsg .= '

Kemungkinan email akan sampai agak terlambat, karena email server kami sedang mengalami sedikit kendala teknis. Jika anda belum juga mendapatkan email, maka jangan ragu untuk laporkan kepada kami melalu email: report@phpindonesia.or.id'; + $successMsg = '

Kemungkinan email akan sampai agak terlambat, karena email server kami sedang mengalami sedikit kendala teknis. Jika anda belum juga mendapatkan email, maka jangan ragu untuk laporkan kepada kami melalu email: report@phpindonesia.or.id'; } $this->addFormAlert('success', $successMsg . '. Terima kasih ^_^.'); @@ -206,6 +203,6 @@ function ($query) use ($args) { $this->addFormAlert('error', 'Bad Request'); } - return $response->withRedirect($this->router->pathFor('membership-login')); + $response->withRedirectRoute('membership-login'); } } diff --git a/app/src/Controllers/PortfoliosController.php b/app/src/Http/Controllers/PortfoliosController.php similarity index 67% rename from app/src/Controllers/PortfoliosController.php rename to app/src/Http/Controllers/PortfoliosController.php index 966207f..c8b03e9 100644 --- a/app/src/Controllers/PortfoliosController.php +++ b/app/src/Http/Controllers/PortfoliosController.php @@ -1,19 +1,18 @@ data(Models\Careers::class); - /** @var \PDOStatement $portfolio */ - $portfolio = $this->data(Models\MemberPortfolios::class)->find([ + $career = new Models\Careers; + $portfolio = (new Models\MemberPortfolios)->find([ 'member_portfolio_id' => (int) $args['id'], 'user_id' => $this->session->get('user_id'), 'deleted' => 'N', @@ -28,33 +27,31 @@ public function index(Request $request, Response $response, array $args) $this->view->addData([ 'career_levels' => array_pairs($career->getLevels(), 'career_level_id'), 'industries' => array_pairs($career->getIndustries(), 'industry_id', 'industry_name') - ], 'sections::portfolio-form'); + ], 'section::portfolio-form'); - return $this->view->render('portfolio-edit', [ + return $response->view('portfolio-edit', [ 'portfolio' => $portfolio->fetch(), ]); } - public function addPage(Request $request, Response $response, array $args) + public function addPage(Response $response) { $this->setPageTitle('Membership', 'Add new portfolio'); - /** @var \Membership\Models\Careers $career */ - $career = $this->data(Models\Careers::class); + $career = new Models\Careers; $this->view->addData([ 'career_levels' => array_pairs($career->getLevels(), 'career_level_id'), 'industries' => array_pairs($career->getIndustries(), 'industry_id', 'industry_name') - ], 'sections::portfolio-form'); + ], 'section::portfolio-form'); - return $this->view->render('portfolio-add'); + return $response->view('portfolio-add'); } - public function add(Request $request, Response $response, array $args) + public function add(Request $request, Response $response) { $input = $request->getParsedBody(); - /** @var \Membership\Models\MemberPortfolios $portfolio */ - $portfolio = $this->data(Models\MemberPortfolios::class); + $portfolio = new Models\MemberPortfolios; $validator = $this->validator->rule('required', [ 'company_name', @@ -85,17 +82,16 @@ public function add(Request $request, Response $response, array $args) } else { $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - return $response->withRedirect($this->router->pathFor('membership-portfolios-add')); + return $response->withRedirectRoute('membership-portfolios-add'); } - return $response->withRedirect($this->router->pathFor('membership-account')); + return $response->withRedirectRoute('membership-account'); } public function edit(Request $request, Response $response, array $args) { $input = $request->getParsedBody(); - /** @var \Membership\Models\MemberPortfolios $portfolio */ - $portfolio = $this->data(Models\MemberPortfolios::class); + $portfolio = new Models\MemberPortfolios; $validator = $this->validator->rule('required', [ 'company_name', 'industry_id', @@ -126,20 +122,18 @@ public function edit(Request $request, Response $response, array $args) } else { $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - return $response->withRedirect($this->router->pathFor('membership-portfolios-edit', $args)); + return $response->withRedirectRoute('membership-portfolios-edit', $args); } - return $response->withRedirect($this->router->pathFor('membership-account')); + return $response->withRedirectRoute('membership-account'); } - public function deleted(Request $request, Response $response, array $args) + public function deleted(Response $response) { $this->addFormAlert('warning', 'This feature is disabled'); - return $response->withRedirect( - $this->router->pathFor('membership-profile', [ - 'username' => $this->session->get('username') - ]) - ); + return $response->withRedirectRoute('membership-profile', [ + 'username' => $this->session->get('username') + ]); } } diff --git a/app/src/Controllers/RegionalsController.php b/app/src/Http/Controllers/RegionalsController.php similarity index 62% rename from app/src/Controllers/RegionalsController.php rename to app/src/Http/Controllers/RegionalsController.php index 4acfa71..481578f 100644 --- a/app/src/Controllers/RegionalsController.php +++ b/app/src/Http/Controllers/RegionalsController.php @@ -1,9 +1,10 @@ assertXhrRequest($request, $response); - /** @var array|false $cities */ - if (!$cities = $this->data(Regionals::class)->getCities($args['province_id'])) { + if (!$cities = (new Regionals)->getCities($args['province_id'])) { throw new NotFoundException($request, $response); } @@ -25,6 +25,6 @@ public function provinces(Request $request, Response $response, array $args) { $this->assertXhrRequest($request, $response); - return $request->withJson($this->data(Regionals::class)->getProvinces()); + return $response->withJson((new Regionals)->getProvinces()); } } diff --git a/app/src/Controllers/SkillsController.php b/app/src/Http/Controllers/SkillsController.php similarity index 64% rename from app/src/Controllers/SkillsController.php rename to app/src/Http/Controllers/SkillsController.php index f3e1059..7372867 100644 --- a/app/src/Controllers/SkillsController.php +++ b/app/src/Http/Controllers/SkillsController.php @@ -1,9 +1,10 @@ assertXhrRequest($request, $response); - /** @var array|false $skills */ - if (!$skills = $this->data(Models\Skills::class)->getChilds($args['id'])) { + if (!$skills = (new Models\Skills)->getChilds($args['id'])) { throw new NotFoundException($request, $response); } return $response->withJson($skills); } - public function addPage(Request $request, Response $response, array $args) + public function addPage(Request $request, Response $response) { $this->setPageTitle('Membership', 'Add new techno skill item'); - /** @var \Membership\Models\Skills $skills */ - $skills = $this->data(Models\Skills::class); + $skills = new Models\Skills; $provinceId = $request->getParam('province_id'); - return $this->view->render('skills-add', [ + return $response->view('skills-add', [ 'skills_main' => array_pairs($skills->getParents(), 'skill_id', 'skill_name'), 'skills' => array_pairs($skills->getChilds($provinceId), 'skill_id', 'skill_name'), ]); } - public function add(Request $request, Response $response, array $args) + public function add(Request $request, Response $response) { $input = $request->getParsedBody(); $requiredFields = [ @@ -50,7 +49,7 @@ public function add(Request $request, Response $response, array $args) $validator = $this->validator->rule('required', $requiredFields); if ($validator->validate()) { - $this->data(Models\MemberSkills::class)->create([ + (new Models\MemberSkills)->create([ 'user_id' => $this->session->get('user_id'), 'skill_id' => $input['skill_id'] ?: $input['skill_parent_id'], 'skill_parent_id' => $input['skill_parent_id'], @@ -61,23 +60,22 @@ public function add(Request $request, Response $response, array $args) } else { $this->addFormAlert('warning', 'Some of mandatory fields is empty!', $validator->errors()); - return $response->withRedirect($this->router->pathFor('membership-skills-add')); + return $response->withRedirectRoute('membership-skills-add'); } - return $response->withRedirect($this->router->pathFor('membership-account')); + return $response->withRedirectRoute('membership-account'); } - public function edit(Request $request, Response $response, array $args) + public function edit(Response $response) { $this->addFormAlert('error', 'Page you just visited, not available at this time'); - return $response->withRedirect($this->router->pathFor('membership-account')); + return $response->withRedirectRoute('membership-account'); } - public function delete(Request $request, Response $response, array $args) + public function delete(Response $response, array $args) { - /** @var MemberSkills $skills */ - $skills = $this->data(Models\MemberSkills::class); + $skills = new Models\MemberSkills(); if ($skills->delete((int) $args['id'])) { $this->addFormAlert('success', 'Item Skill berhasil dihapus.'); @@ -85,6 +83,6 @@ public function delete(Request $request, Response $response, array $args) $this->addFormAlert('error', 'Sesuatu terjadi, skill gagal dihapus.'); } - return $response->withRedirect($this->router->pathFor('membership-account')); + return $response->withRedirectRoute('membership-account'); } } diff --git a/app/src/Middleware.php b/app/src/Http/Middleware.php similarity index 80% rename from app/src/Middleware.php rename to app/src/Http/Middleware.php index f81f023..b73bfde 100644 --- a/app/src/Middleware.php +++ b/app/src/Http/Middleware.php @@ -1,18 +1,21 @@ authorizeOwnership($request, Models\MemberPortfolios::class)) { + if (!$this->authorizeOwnership($request, MemberPortfolios::class)) { return $this->responseWithDenial($request, $response); } @@ -89,10 +92,10 @@ public function authorizePorfolioRoute(Request $request, Response $response, cal } /** - * @param \Slim\Http\Request $request - * @param \Slim\Http\Response $response - * @param callable $next - * @return \Slim\Http\Response + * @param Request $request + * @param Response $response + * @param callable $next + * @return Response */ public function authorizeSkillRoute(Request $request, Response $response, callable $next) { @@ -102,7 +105,7 @@ public function authorizeSkillRoute(Request $request, Response $response, callab } // Validate request with existing model - if (!$this->authorizeOwnership($request, Models\MemberSkills::class)) { + if (!$this->authorizeOwnership($request, MemberSkills::class)) { return $this->responseWithDenial($request, $response); } @@ -110,9 +113,9 @@ public function authorizeSkillRoute(Request $request, Response $response, callab } /** - * @param \Slim\Http\Request $request - * @param \Slim\Http\Response $response - * @return \Slim\Http\Response + * @param Request $request + * @param Response $response + * @return Response */ private function responseWithDenial(Request $request, Response $response) { @@ -130,7 +133,7 @@ private function responseWithDenial(Request $request, Response $response) } /** - * @param \Slim\Http\Request $request + * @param Request $request * @return bool */ private function isAcceptable(Request $request) @@ -141,13 +144,13 @@ private function isAcceptable(Request $request) } /** - * @param \Slim\Http\Request $request - * @param string $model + * @param Request $request + * @param string $model * @return bool */ private function authorizeOwnership(Request $request, $model) { - $data = $this->data($model); + $data = new $model; $args = $request->getAttribute('routeInfo')[2]; if (!$ownerId = $this->getOwnerId($request)) { @@ -158,7 +161,7 @@ private function authorizeOwnership(Request $request, $model) } /** - * @param \Slim\Http\Request $request + * @param Request $request * @return bool|int */ private function getOwnerId(Request $request) @@ -179,7 +182,7 @@ private function getOwnerId(Request $request) } } - $users = $this->data(Models\Users::class); + $users = new Users; $user = $users->get([$users->primary(), 'password', 'username'], ['username' => $username])->fetch(); $salt = $this->settings->get('salt_pwd'); diff --git a/app/src/Http/Request.php b/app/src/Http/Request.php new file mode 100644 index 0000000..973c036 --- /dev/null +++ b/app/src/Http/Request.php @@ -0,0 +1,74 @@ +validator = $validator($this); + + return $this; + } + + public function rules($rules, $fields = []) + { + if (is_string($rules) && $fields) { + $this->validator->rule($rules, $fields); + } else { + $this->validator->rules($rules); + } + + return $this; + } + + /** + * Validate request based on model rules + * + * @param callable|Models $model + * @param callable|null $callback + * @return Collection + * @throws ValidatorException + */ + public function validate($model, callable $callback = null) + { + if (null === $this->validator) { + return null; + } + + if ($model instanceof Models && is_callable($callback)) { + $rules = method_exists($model, 'rules') && is_callable([$model, 'rules']) + ? $model->rules($this->validator) + : []; + + $this->validator->rules($rules); + } elseif (is_callable($model)) { + $callback = $model; + } + + if (! $this->validator->validate()) { + throw new ValidatorException('Invalid request input', $this->validator->errors()); + } + + $input = new Collection($this->getParsedBody()); + + if ($callback) { + return $model instanceof Models ? $callback($input, $model) : $callback($input); + } + + return $input; + } +} diff --git a/app/src/Http/Response.php b/app/src/Http/Response.php new file mode 100644 index 0000000..90777e3 --- /dev/null +++ b/app/src/Http/Response.php @@ -0,0 +1,66 @@ +view = $view->getPlates(); + + return $this; + } + + /** + * @param RouterInterface $router + * @return static + */ + public function setRouter(RouterInterface $router) + { + $this->router = $router; + + return $this; + } + + /** + * Redirect to route + * + * @param string $name + * @param array $args + * @return static + */ + public function withRedirectRoute($name, $args = []) + { + $clone = clone $this; + + return $clone->withRedirect($this->router->pathFor($name, $args)); + } + + /** + * @param string $name + * @param array $data + * @return \Psr\Http\Message\ResponseInterface + */ + public function view($name, array $data = []) + { + return $this->write($this->view->render($name, $data)); + } +} diff --git a/app/src/Http/ValidatorException.php b/app/src/Http/ValidatorException.php new file mode 100644 index 0000000..0f1691f --- /dev/null +++ b/app/src/Http/ValidatorException.php @@ -0,0 +1,20 @@ +errors = $errors; + } + + public function getErrors() + { + return $this->errors; + } +} diff --git a/app/src/Libraries/Mailer.php b/app/src/Libraries/Mailer.php deleted file mode 100644 index c51723b..0000000 --- a/app/src/Libraries/Mailer.php +++ /dev/null @@ -1,176 +0,0 @@ - '', - 'port' => '', - 'username' => '', - 'password' => '', - 'auth' => true, - 'secure' => 'tsl', - 'senderEmail' => '', - 'senderName' => '', - ]; - - /** - * Debug mode - * - * @var array - */ - private $debugMode = [ - 'debug' => 3, - 'development' => 2, - 'production' => 1, - 'testing' => 0, - ]; - - /** - * Mailer constructor. - * - * @param array $settings - * @throws \InvalidArgumentException - */ - public function __construct(array $settings = [], Engine $view) - { - $this->view = $view; - $settings = array_merge($this->settings, $settings); - - $this->mail = new \PHPMailer(true); - - $this->mail->Host = $settings['host']; - $this->mail->Port = $settings['port']; - $this->mail->Username = $settings['username']; - $this->mail->Password = $settings['password']; - - $this->mail->isSMTP(); - - $this->mail->SMTPAuth = $settings['auth']; - $this->mail->SMTPSecure = $settings['secure']; - } - - /** - * Setup Sender - * - * @param string $senderEmail - * @param string $senderName - */ - public function setSender($senderEmail, $senderName) - { - $this->mail->setFrom($senderEmail, $senderName); - - return $this; - } - - /** - * Set mailer debug mode - * - * @param string $mode - * @return $this - */ - public function debugMode($mode) - { - if (!isset($this->debugMode[$mode])) { - $mode = 'production'; - } - - $this->mail->SMTPDebug = $this->debugMode[$mode]; - - return $this; - } - - /** - * Add recipient email address. - * - * @param string $address - * @return $this - */ - public function to($address, $name = '') - { - $this->mail->addAddress($address, $name); - - return $this; - } - - /** - * Add email subject. - * - * @param string $subject - * @return $this - */ - public function withSubject($subject) - { - $this->mail->Subject = $subject; - - return $this; - } - - /** - * Write email body. - * - * @param string $body - * @param array $data - * @return $this - */ - public function withBody($body, array $data = []) - { - if (strpos($body, '::') !== false) { - if (!$this->view instanceof Engine) { - throw new \LogicException('View must be instance of ' . Engine::class); - } - - $this->mail->isHTML(true); - - $body = $this->view->render($body, $data); - } - - $this->mail->Body = $body; - - return $this; - } - - /** - * Add attachments. - * - * @param array $attachments - * @return $this - */ - public function addAttachments(array $files) - { - /** @var string $filepath */ - foreach ($files as $filepath) { - $this->mail->addAttachment($filepath); - } - - return $this; - } - - /** - * Send the thing. - * - * @return mixed - */ - public function send() - { - return $this->mail->send(); - } -} diff --git a/app/src/Libraries/PDO/Database.php b/app/src/Libraries/PDO/Database.php deleted file mode 100644 index 01c707b..0000000 --- a/app/src/Libraries/PDO/Database.php +++ /dev/null @@ -1,20 +0,0 @@ -container[] = ' '.$chainType.' '.$column; - } - else - { - $this->container[] = ' '.$chainType.' '.$column.' '.$operator.' ?'; - } - } -} diff --git a/app/src/Mail.php b/app/src/Mail.php new file mode 100644 index 0000000..d46fecd --- /dev/null +++ b/app/src/Mail.php @@ -0,0 +1,106 @@ + Mail\SmtpMessage::class, + 'sparkpost' => Mail\SparkpostMessage::class, + ]; + + /** + * @var Mail\MessageInterface + */ + protected $adapter = null; + + /** + * @var \League\Plates\Engine + */ + protected $view; + + /** + * Create new Mail instance. + * + * @param Mail\MessageInterface $adapter + * @param Plates $view + * @param array $appSettings + * @throws \Exception + */ + public function __construct(Mail\MessageInterface $adapter, Plates $view, $appSettings = []) + { + if ($appSettings) { + $adapter->from($appSettings['email'], $appSettings['name']); + } + + $this->adapter = $adapter; + $this->view = $view->getPlates(); + } + + /** + * Add recipient(s). + * + * @param array|string $address + * @param string $name + * @return static + */ + public function to($address, $name = '') + { + $this->adapter->to($address, $name); + + return $this; + } + + /** + * Add sender. + * + * @param array|string $address + * @param string $name + * @return static + */ + public function from($address, $name = '') + { + $this->adapter->from($address, $name); + + return $this; + } + + /** + * Add subject. + * + * @param array|string $subject + * @return static + */ + public function subject($subject) + { + $this->adapter->subject($subject); + + return $this; + } + + /** + * Send the email. + * + * @param string|array $view + * @param array $data + * @param callable $callback + */ + public function send($view, array $data = [], callable $callback = null) + { + if ($callback) { + $callback($this->adapter); + } + + $this->adapter->content( + $this->view->render($view, $data) + ); + + $this->adapter->send(); + } +} diff --git a/app/src/Mail/MessageException.php b/app/src/Mail/MessageException.php new file mode 100644 index 0000000..32fac08 --- /dev/null +++ b/app/src/Mail/MessageException.php @@ -0,0 +1,8 @@ + 3, + 'development' => 2, + 'production' => 1, + 'testing' => 0, + ]; + + public function __construct(\PHPMailer $mailer) + { + $this->mailer = $mailer; + } + + public function debugMode($mode) + { + if (!isset($this->debugMode[$mode])) { + $mode = 'production'; + } + + $this->mailer->SMTPDebug = $this->debugMode[$mode]; + + return $this; + } + + public function from($address, $name) + { + $this->mailer->setFrom($address, $name); + + return $this; + } + + public function to($address, $name = '') + { + $this->mailer->addAddress($address, $name); + + return $this; + } + + public function subject($subject) + { + $this->mailer->Subject = $subject; + + return $this; + } + + public function content($body) + { + $this->mailer->Body = $body; + + return $this; + } + + public function attach(array $files) + { + foreach ($files as $filepath) { + $this->mailer->addAttachment($filepath); + } + + return $this; + } + + public function send() + { + try { + return $this->mailer->send(); + } catch (\phpmailerException $e) { + throw new MessageException($e->getMessage(), $e->getCode()); + } + } +} diff --git a/app/src/Mail/SparkpostMessage.php b/app/src/Mail/SparkpostMessage.php new file mode 100644 index 0000000..376fe8e --- /dev/null +++ b/app/src/Mail/SparkpostMessage.php @@ -0,0 +1,100 @@ +client = $mailer; + $this->key = $key; + } + + public function from($address, $name) + { + $this->content['from'] = ['name' => $name, 'email' => $address]; + + return $this; + } + + public function to($address, $name = '') + { + $this->recipients[] = [ + 'address' => ['name' => $name, 'email' => $address] + ]; + + return $this; + } + + public function subject($subject) + { + $this->content['subject'] = $subject; + + return $this; + } + + public function content($body) + { + $this->content['html'] = $body; + + return $this; + } + + public function attach(array $files) + { + return $this; + } + + public function send() + { + try { + $headers = [ + 'Authorization' => $this->key, + 'Content-Type' => 'application/json' + ]; + + $body = [ + 'recipients' => $this->recipients, + 'content' => $this->content, + 'options' => [ + 'transactional' => true, + 'open_tracking' => true, + 'click_tracking' => true, + ], + ]; + + /** @var \Psr\Http\Message\RequestInterface $request */ + $request = (new SlimMessageFactory) + ->createRequest('POST', self::ENDPOINT, $headers, json_encode($body, true)); + + /** @var \Psr\Http\Message\ResponseInterface $response */ + $response = $this->client->sendRequest($request); + + return $response->getStatusCode() === 200; + } catch (RequestException $e) { + throw new MessageException($e->getMessage(), $e->getCode()); + } + } +} diff --git a/app/src/Models.php b/app/src/Models.php index 55df087..6c13d1d 100644 --- a/app/src/Models.php +++ b/app/src/Models.php @@ -1,17 +1,13 @@ db = $db; - $this->session = $session; + global $container; + + if (! $this->db) { + $this->db = $container->get('db'); + $this->session = $container->get('session'); + } } /** - * Retrieve current user session + * @return Database + */ + protected static function db() + { + global $container; + + return $container->get('db'); + } + + /** + * Retrieve current user session. * * @param string $key * @param string $default - * @return int + * @return \Slim\Interfaces\CollectionInterface|mixed */ protected function current($key = null, $default = null) { - if (is_null($this->session)) { - return $default; - } + global $container; + + $session = $container->get('session'); - if (!is_null($key)) { - return $this->session->get($key, $default); + if (! is_null($key)) { + return $session->get($key, $default); } - return $this->session; + return $session; } /** - * Create new data + * Create new database * - * @param array $pairs column value pairs of data + * @param array|Collection $pairs column value pairs of database * @return int|false */ - public function create(array $pairs) + public function create($pairs) { if (!$this->table) { return false; } + if ($pairs instanceof Collection) { + $pairs = $pairs->all(); + } + $this->authorize('create', $pairs); if (false === $this->destructive) { $pairs['deleted'] = 'N'; } - $query = $this->db->insert(array_keys($pairs)) + $query = static::db()->insert(array_keys($pairs)) ->into($this->table) ->values(array_values($pairs)); @@ -97,10 +116,10 @@ public function create(array $pairs) } /** - * Get basic data + * Get basic database * * @param string[] $columns Array of column - * @param callable|array|int $terms column value pairs of term data you wanna find to + * @param callable|array|int $terms column value pairs of term database you wanna find to * @return \PDOStatement|false */ public function get(array $columns = [], $terms = null) @@ -109,7 +128,7 @@ public function get(array $columns = [], $terms = null) return false; } - $query = $this->db->select($columns)->from($this->table); + $query = static::db()->select($columns)->from($this->table); $this->normalizeTerms($query, $terms); @@ -119,7 +138,7 @@ public function get(array $columns = [], $terms = null) /** * Find existing item(s) from table * - * @param callable|array|int $terms column value pairs of term data you wanna find to + * @param callable|array|int $terms column value pairs of term database you wanna find to * @return \PDOStatement|false */ public function find($terms = null) @@ -130,11 +149,11 @@ public function find($terms = null) /** * Update existing item from table * - * @param array $pairs column value pairs of data - * @param callable|array|int $terms column value pairs of term data you wanna update to + * @param array|Collection $pairs column value pairs of database + * @param callable|array|int $terms column value pairs of term database you wanna update to * @return int|false */ - public function update(array $pairs, $terms = null) + public function update($pairs, $terms = null) { if (!$this->table) { return false; @@ -142,7 +161,7 @@ public function update(array $pairs, $terms = null) $this->authorize('update', $pairs); - $query = $this->db->update(array_filter($pairs))->table($this->table); + $query = static::db()->update(array_filter($pairs))->table($this->table); $this->normalizeTerms($query, $terms); @@ -165,7 +184,7 @@ public function delete($terms) return $this->update(['deleted' => 'Y'], $terms); } - $query = $this->db->delete($this->table); + $query = static::db()->delete($this->table); $this->normalizeTerms($query, $terms); @@ -173,7 +192,7 @@ public function delete($terms) } /** - * Count all data + * Count all database * * @param callable|array|int $terms Use it if you want more terms * @param string $column Column to count @@ -186,13 +205,33 @@ public function count($terms = null, $column = '', $distinct = false) return 0; } - $query = $this->db->select()->count(($column ?: '*'), 'count', $distinct)->from($this->table); + $query = static::db()->select()->count(($column ?: '*'), 'count', $distinct)->from($this->table); $this->normalizeTerms($query, $terms); return (int) $query->execute()->fetch()['count']; } + /** + * Determine is $value is exists in $field + * + * @param string $field + * @param string|array $value + * @return bool + */ + public function isExists($field, $value) + { + $count = $this->count(function (StatementContainer $query) use ($field, $value) { + if (is_array($value)) { + $query->whereIn($field, $value); + } else { + $query->where($field, '=', strtolower($value)); + } + }); + + return $count > 0; + } + /** * Retrieve table primary key * @@ -206,8 +245,8 @@ public function primary() /** * Normalize query terms * - * @param \Slim\PDO\Statement\StatementContainer $query - * @param callable|array|int $terms + * @param StatementContainer $query + * @param callable|array|int $terms * @return void */ protected function normalizeTerms(StatementContainer $query, &$terms) diff --git a/app/src/Models/Careers.php b/app/src/Models/Careers.php index 7935657..346af1c 100644 --- a/app/src/Models/Careers.php +++ b/app/src/Models/Careers.php @@ -1,10 +1,14 @@ 'KTP', 'sim' => 'SIM', 'ktm' => 'Kartu Mahasiswa']; + const GENDERS = ['female' => 'Wanita', 'male' => 'Pria']; + /** * {@inheritdoc} */ @@ -22,12 +27,65 @@ class Users extends Models protected $authorize = true; /** - * Create new user data - * - * @param string[] $pairs user data - * @return int|false + * @param Validator|null $validator + * @return array + */ + public function rules(Validator $validator = null) + { + $validator->addRule('notExists', function ($field, $value) { + return ! $this->isExists($field, $value); + }, 'tersebut sudah terdaftar!'); + + $validator->addRule('usable', function ($field, $value) { + return ! in_array($value, [ + 'admin', + 'account', 'login', 'register', 'logout', + 'activate', 'reactivate', 'regionals', + 'forgot-password', 'reset-password' + ]); + }, 'tersebut tidak diijinkan!'); + + return [ + 'regex' => [ + ['fullname', ':^[A-z\s]+$:'], + ['username', ':^[A-z\d\-\.\_]+$:'], + ['contact_phone', ':^[-\+\d]+$:'], + ['identity_number', ':^[^\W_]+$:'], + ], + 'email' => 'email', + 'usable' => 'username', + 'notExists' => [ + ['email'], + ['username'] + ], + 'dateFormat' => [ + ['birth_date', 'Y-m-d'] + ], + 'equals' => [ + ['repassword', 'password'] + ], + 'in' => [ + ['identity_type', array_keys(static::IDENTITY_TYPES)] + ], + 'lengthMax' => [ + ['fullname', 32], + ['username', 64], + ['contact_phone', 16], + ['area', 64], + ['identity_number', 32], + ['birth_place', 32], + ], + 'lengthMin' => [ + ['username', 6], + ['password', 6], + ] + ]; + } + + /** + * @inheritdoc */ - public function create(array $pairs) + public function create($pairs) { $this->db->beginTransaction(); $pairs['city_id'] = 0; @@ -88,7 +146,7 @@ public function create(array $pairs) } /** - * Update user login data + * Update user login database * * @param int $userId User ID * @return int diff --git a/app/src/Models/UsersActivations.php b/app/src/Models/UsersActivations.php index 31115ba..c6910e4 100644 --- a/app/src/Models/UsersActivations.php +++ b/app/src/Models/UsersActivations.php @@ -1,4 +1,5 @@ db->commit(); return true; - } catch (Exception $e) { + } catch (\Exception $e) { $this->db->rollback(); return false; diff --git a/app/src/Models/UsersResetPwd.php b/app/src/Models/UsersResetPwd.php index 42cc14e..9d7e42a 100644 --- a/app/src/Models/UsersResetPwd.php +++ b/app/src/Models/UsersResetPwd.php @@ -1,4 +1,5 @@ addData([ 'validation_errors' => [], 'base_js' => [], @@ -86,7 +89,7 @@ public function register(Engine $engine) */ public function userPhoto($publicId = null, $options = []) { - $default = $this->template->asset('/images/team.png'); + $default = $this->template->asset('asset/images/team.png'); if (null === $publicId) { return $default; } @@ -138,10 +141,10 @@ public function inputMethod($method) } /** - * Generate form based on $database array * * @param string $name Name attribute - * @param array $data List of data + * @param array $data List of database * @param array $attributes Optiona html attributes * @return string */ @@ -164,10 +167,10 @@ public function inputSelect($name, array $data, array $attributes = []) foreach ($data as $key => $value) { $selected = ''; if ($key == $reqInput) { - $selected = ' selected="selected"'; + $selected = 'selected="selected"'; } - $elements[] = ''; + $elements[] = ''; } $elements[] = ''; @@ -182,14 +185,18 @@ public function inputSelect($name, array $data, array $attributes = []) */ public function fieldError($name) { - if ($error = $this->flash->getMessage('validation.errors.'.$name)) { + if ($error = $this->flash->getMessage('validation._errors.'.$name)) { return '

'.implode(', ', $error).'

'; } + + return ''; } /** * Generate pagination links * + * @param int $dataTotal + * @param int $perPage * @return string */ public function dataPagerLinks($dataTotal, $perPage) @@ -230,10 +237,10 @@ public function dataPagerLinks($dataTotal, $perPage) if ($i === $pageNum) { $url = '#'; - $active = ' class="active"'; + $active = 'class="active"'; } - $elements[] = '
  • '.$i.'
  • '; + $elements[] = '
  • '.$i.'
  • '; } // To next diff --git a/app/src/helpers.php b/app/src/helpers.php index 37fa311..28d4676 100644 --- a/app/src/helpers.php +++ b/app/src/helpers.php @@ -33,8 +33,7 @@ function array_pairs(array $values, $key, $val = null) */ function array_flatten(array $array) { - $array = array_values($array); - return call_user_func_array('array_merge', $array); + return call_user_func_array('array_merge', array_values($array)); } } @@ -138,3 +137,17 @@ function days_range() return $days_range; } } + +if (! function_exists('env')) { + /** + * Get environment variable. + * + * @param string $name + * @param mixed $default + * @return string + */ + function env($name, $default = null) + { + return getenv($name) ?: $default; + } +} diff --git a/app/views/emails/activation.php b/app/views/_emails/activation.php similarity index 86% rename from app/views/emails/activation.php rename to app/views/_emails/activation.php index fae67bd..7fd8bde 100644 --- a/app/views/emails/activation.php +++ b/app/views/_emails/activation.php @@ -4,7 +4,7 @@

    Demi keamanan dan validitas data, maka kami mewajibkan setiap registrant untuk melakukan aktivasi account melalui email.

    -

    Maka dari itu, anda dapat mengaktifkan account anda melalui akses url aktivasi berikut: e($activationUrl) ?>.
    +

    Maka dari itu, anda dapat mengaktifkan account anda melalui akses url aktivasi berikut: baseUrl($activationUrl) ?>.
    Url activation ini akan expired pada: e($activationExp) ?>

    Jika anda tidak pernah merasa melakukan submission, maka anda dapat mengabaikan email ini.
    diff --git a/app/views/emails/forgot-password.php b/app/views/_emails/forgot-password.php similarity index 90% rename from app/views/emails/forgot-password.php rename to app/views/_emails/forgot-password.php index e17b3a7..0718c45 100644 --- a/app/views/emails/forgot-password.php +++ b/app/views/_emails/forgot-password.php @@ -4,7 +4,7 @@

    Kami butuh konfirmasi anda untuk memastikan bahwa anda memang benar-benar telah melakukan permintaan perubahan password sesuai kehendak anda.

    -

    Jika permintaan perubahan password ini memang sesuai dengan kehendak anda, maka silahkan klik link e($resetUrl) ?> untuk melakukan konfirmasi.

    +

    Jika permintaan perubahan password ini memang sesuai dengan kehendak anda, maka silahkan klik link baseUrl($resetUrl) ?> untuk melakukan konfirmasi.

    Jika permintaan perubahan password ini bukan kehendak anda, maka email ini bisa diabaikan saja atau Anda dapat melaporkannya kepada kami melalui email report@phpindonesia.or.id

    diff --git a/app/views/emails/reset-password.php b/app/views/_emails/reset-password.php similarity index 100% rename from app/views/emails/reset-password.php rename to app/views/_emails/reset-password.php diff --git a/app/views/errors/500.php b/app/views/_errors/500.php similarity index 100% rename from app/views/errors/500.php rename to app/views/_errors/500.php diff --git a/app/views/layouts/account.php b/app/views/_layouts/account.php similarity index 86% rename from app/views/layouts/account.php rename to app/views/_layouts/account.php index 5e666a4..d55fdd6 100644 --- a/app/views/layouts/account.php +++ b/app/views/_layouts/account.php @@ -1,11 +1,11 @@ -layout('layouts::system') ?> +layout('layout::system') ?>
    - insert('sections::alert') ?> + insert('section::alert') ?> section('content') ?>
    @@ -19,6 +19,7 @@

    +

    ', $helpContent) ?>

    diff --git a/app/views/layouts/system.php b/app/views/_layouts/system.php similarity index 56% rename from app/views/layouts/system.php rename to app/views/_layouts/system.php index f4f2058..9c67dcb 100644 --- a/app/views/layouts/system.php +++ b/app/views/_layouts/system.php @@ -10,24 +10,24 @@ PHP Indonesia | Membership - - - - - - - + + + + + + + + + - - + @@ -35,7 +35,7 @@
    - insert('sections::header') ?> + insert('section::header') ?>
    - - - - - - - - + + + + + + + + diff --git a/app/views/sections/alert.php b/app/views/_sections/alert.php similarity index 100% rename from app/views/sections/alert.php rename to app/views/_sections/alert.php diff --git a/app/views/sections/captcha.php b/app/views/_sections/captcha.php similarity index 100% rename from app/views/sections/captcha.php rename to app/views/_sections/captcha.php diff --git a/app/views/sections/footer.php b/app/views/_sections/footer.php similarity index 69% rename from app/views/sections/footer.php rename to app/views/_sections/footer.php index 95cea11..f8ee2da 100644 --- a/app/views/sections/footer.php +++ b/app/views/_sections/footer.php @@ -13,12 +13,12 @@
    @@ -38,8 +38,8 @@
    - insert('sections::captcha') ?> + insert('section::captcha') ?>
    diff --git a/app/views/portfolio-add.php b/app/views/portfolio-add.php index 548c805..c54a90b 100644 --- a/app/views/portfolio-add.php +++ b/app/views/portfolio-add.php @@ -1,8 +1,8 @@ layout('layouts::system'); +$this->layout('layout::system'); $this->appendJs([ - $this->asset('/js/portfolio.js') + $this->asset('asset/js/portfolio.js') ]); ?> @@ -13,10 +13,10 @@

    Add new portfolio item

    - insert('sections::alert') ?> + insert('section::alert') ?> - insert('sections::portfolio-form', ['portfolio' => false]) ?> + insert('section::portfolio-form', ['portfolio' => false]) ?>
    diff --git a/app/views/portfolio-edit.php b/app/views/portfolio-edit.php index 1eb0985..200e9bd 100644 --- a/app/views/portfolio-edit.php +++ b/app/views/portfolio-edit.php @@ -1,8 +1,8 @@ layout('layouts::system'); +$this->layout('layout::system'); $this->appendJs([ - $this->asset('/js/portfolio.js') + $this->asset('asset/js/portfolio.js') ]); ?> @@ -13,13 +13,13 @@

    Edit Portfolio Item

    - insert('sections::alert') ?> + insert('section::alert') ?>
    formInputMethod('PUT') ?> - insert('sections::portfolio-form', ['portfolio' => $portfolio]) ?> + insert('section::portfolio-form', ['portfolio' => $portfolio]) ?>
    diff --git a/app/views/profile-index.php b/app/views/profile-index.php index 00b240a..e5023d5 100644 --- a/app/views/profile-index.php +++ b/app/views/profile-index.php @@ -1,8 +1,8 @@ -layout('layouts::system'); +layout('layout::system'); $this->appendCss([ - $this->asset('/css/profile.css') + $this->asset('asset/css/profile.css') ]); ?> diff --git a/app/views/skills-add.php b/app/views/skills-add.php index 12fced8..3bd0f88 100644 --- a/app/views/skills-add.php +++ b/app/views/skills-add.php @@ -1,8 +1,8 @@ layout('layouts::system'); +$this->layout('layout::system'); $this->appendJs([ - $this->asset('/js/skill.js') + $this->asset('asset/js/skill.js') ]); ?> @@ -13,7 +13,7 @@

    Add new techno skill item

    - insert('sections::alert') ?> + insert('section::alert') ?>

    Jika Skill Global tidak memunculkan Spesific Item, Maka silahkan langsung saja nilai menggunakan skill global. diff --git a/www/css/bootstrap.css b/asset/css/bootstrap.css similarity index 100% rename from www/css/bootstrap.css rename to asset/css/bootstrap.css diff --git a/www/css/chabibnr.css b/asset/css/chabibnr.css similarity index 100% rename from www/css/chabibnr.css rename to asset/css/chabibnr.css diff --git a/www/css/font-awesome.css b/asset/css/font-awesome.css similarity index 100% rename from www/css/font-awesome.css rename to asset/css/font-awesome.css diff --git a/www/css/formalize.css b/asset/css/formalize.css similarity index 100% rename from www/css/formalize.css rename to asset/css/formalize.css diff --git a/www/css/index.html b/asset/css/index.html similarity index 100% rename from www/css/index.html rename to asset/css/index.html diff --git a/www/css/profile.css b/asset/css/profile.css similarity index 100% rename from www/css/profile.css rename to asset/css/profile.css diff --git a/www/css/reset.css b/asset/css/reset.css similarity index 100% rename from www/css/reset.css rename to asset/css/reset.css diff --git a/www/css/responsive.css b/asset/css/responsive.css similarity index 100% rename from www/css/responsive.css rename to asset/css/responsive.css diff --git a/www/fonts/fontawesome-webfont.eot b/asset/fonts/fontawesome-webfont.eot similarity index 100% rename from www/fonts/fontawesome-webfont.eot rename to asset/fonts/fontawesome-webfont.eot diff --git a/www/fonts/fontawesome-webfont.svg b/asset/fonts/fontawesome-webfont.svg similarity index 100% rename from www/fonts/fontawesome-webfont.svg rename to asset/fonts/fontawesome-webfont.svg diff --git a/www/fonts/fontawesome-webfont.ttf b/asset/fonts/fontawesome-webfont.ttf similarity index 100% rename from www/fonts/fontawesome-webfont.ttf rename to asset/fonts/fontawesome-webfont.ttf diff --git a/www/fonts/fontawesome-webfont.woff b/asset/fonts/fontawesome-webfont.woff similarity index 100% rename from www/fonts/fontawesome-webfont.woff rename to asset/fonts/fontawesome-webfont.woff diff --git a/www/fonts/fontawesome-webfont.woff2 b/asset/fonts/fontawesome-webfont.woff2 similarity index 100% rename from www/fonts/fontawesome-webfont.woff2 rename to asset/fonts/fontawesome-webfont.woff2 diff --git a/www/fonts/index.html b/asset/fonts/index.html similarity index 100% rename from www/fonts/index.html rename to asset/fonts/index.html diff --git a/www/images/index.html b/asset/images/index.html similarity index 100% rename from www/images/index.html rename to asset/images/index.html diff --git a/www/images/team.png b/asset/images/team.png similarity index 100% rename from www/images/team.png rename to asset/images/team.png diff --git a/www/js/index.html b/asset/js/index.html similarity index 100% rename from www/js/index.html rename to asset/js/index.html diff --git a/www/js/jquery.formalize.min.js b/asset/js/jquery.formalize.min.js similarity index 100% rename from www/js/jquery.formalize.min.js rename to asset/js/jquery.formalize.min.js diff --git a/www/js/jquery.inputmask.bundle.js b/asset/js/jquery.inputmask.bundle.js similarity index 99% rename from www/js/jquery.inputmask.bundle.js rename to asset/js/jquery.inputmask.bundle.js index 2551629..d904288 100644 --- a/www/js/jquery.inputmask.bundle.js +++ b/asset/js/jquery.inputmask.bundle.js @@ -33,13 +33,13 @@ } function importAttributeOptions(npt, opts, userOptions) { function importOption(option) { - var optionData = npt.getAttribute("data-inputmask-" + option.toLowerCase()); + var optionData = npt.getAttribute("database-inputmask-" + option.toLowerCase()); null !== optionData && (optionData = "boolean" == typeof optionData ? optionData : optionData.toString(), "string" == typeof optionData && 0 === option.indexOf("on") && (optionData = eval("(" + optionData + ")")), "mask" === option && 0 === optionData.indexOf("[") ? (userOptions[option] = optionData.replace(/[\s[\]]/g, "").split(","), userOptions[option][0] = userOptions[option][0].replace("'", ""), userOptions[option][userOptions[option].length - 1] = userOptions[option][userOptions[option].length - 1].replace("'", "")) : userOptions[option] = optionData); } - var attrOptions = npt.getAttribute("data-inputmask"); + var attrOptions = npt.getAttribute("database-inputmask"); if (attrOptions && "" !== attrOptions) try { attrOptions = attrOptions.replace(new RegExp("'", "g"), '"'); var dataoptions = $.parseJSON("{" + attrOptions + "}"); diff --git a/www/js/jquery.popupoverlay.js b/asset/js/jquery.popupoverlay.js similarity index 98% rename from www/js/jquery.popupoverlay.js rename to asset/js/jquery.popupoverlay.js index 74af73b..d05a9a5 100644 --- a/www/js/jquery.popupoverlay.js +++ b/asset/js/jquery.popupoverlay.js @@ -30,7 +30,7 @@ zindexvalues[el.id] = 0; if (!$el.data('popup-initialized')) { - $el.attr('data-popup-initialized', 'true'); + $el.attr('database-popup-initialized', 'true'); methods._initonce(el); } @@ -193,7 +193,7 @@ var openelement = (options.openelement) ? options.openelement : ('.' + el.id + opensuffix); $(openelement).each(function (i, item) { - $(item).attr('data-popup-ordinal', i); + $(item).attr('database-popup-ordinal', i); if (!item.id) { $(item).attr('id', 'open_' + parseInt((Math.random() * 100000000), 10)); @@ -258,7 +258,7 @@ if (!$el.data('popup-initialized')) { methods._init(el); } - $el.attr('data-popup-initialized', 'true'); + $el.attr('database-popup-initialized', 'true'); var $body = $('body'); var options = $el.data('popupoptions'); @@ -580,9 +580,9 @@ if (options.tooltipanchor) { $tooltipanchor = $(options.tooltipanchor); } else if (options.openelement) { - $tooltipanchor = $(options.openelement).filter('[data-popup-ordinal="' + ordinal + '"]'); + $tooltipanchor = $(options.openelement).filter('[database-popup-ordinal="' + ordinal + '"]'); } else { - $tooltipanchor = $('.' + el.id + opensuffix + '[data-popup-ordinal="' + ordinal + '"]'); + $tooltipanchor = $('.' + el.id + opensuffix + '[database-popup-ordinal="' + ordinal + '"]'); } var linkOffset = $tooltipanchor.offset(); @@ -664,7 +664,7 @@ var callback = function (el, ordinal, func) { var options = $(el).data('popupoptions'); var openelement = (options.openelement) ? options.openelement : ('.' + el.id + opensuffix); - var elementclicked = $(openelement + '[data-popup-ordinal="' + ordinal + '"]'); + var elementclicked = $(openelement + '[database-popup-ordinal="' + ordinal + '"]'); if (typeof func == 'function') { func.call($(el), el, elementclicked); } diff --git a/www/js/membership.js b/asset/js/membership.js similarity index 100% rename from www/js/membership.js rename to asset/js/membership.js diff --git a/www/js/pencarian.js b/asset/js/pencarian.js similarity index 100% rename from www/js/pencarian.js rename to asset/js/pencarian.js diff --git a/www/js/portfolio.js b/asset/js/portfolio.js similarity index 91% rename from www/js/portfolio.js rename to asset/js/portfolio.js index a474193..37e7176 100644 --- a/www/js/portfolio.js +++ b/asset/js/portfolio.js @@ -19,7 +19,7 @@ $(document).ready(function () { }).done(function (data) { console.log(data); }).fail(function (data) { - alert('Failed to request data'); + alert('Failed to request database'); }).always(function (data) { $('#portfolio-popup').popup('hide'); }); @@ -33,7 +33,7 @@ $(document).ready(function () { }).done(function (data) { console.log(data); }).fail(function (data) { - alert('Failed to request data'); + alert('Failed to request database'); }).always(function (data) { $('#skill-popup').popup('hide'); }); diff --git a/www/js/profile.js b/asset/js/profile.js similarity index 100% rename from www/js/profile.js rename to asset/js/profile.js diff --git a/www/js/regional.js b/asset/js/regional.js similarity index 100% rename from www/js/regional.js rename to asset/js/regional.js diff --git a/www/js/skill.js b/asset/js/skill.js similarity index 95% rename from www/js/skill.js rename to asset/js/skill.js index 221fa69..b265618 100644 --- a/www/js/skill.js +++ b/asset/js/skill.js @@ -26,7 +26,7 @@ $(document).ready(function () { } }).fail(function (data) { - alert('Failed to request data'); + alert('Failed to request database'); }).always(function (data) { // }); diff --git a/composer.json b/composer.json index 3757431..05aa01e 100644 --- a/composer.json +++ b/composer.json @@ -2,17 +2,20 @@ "name": "phpindonesia/membership-2", "description": "PHP Indonesia Membership Application Reloaded", "type": "project", - "minimum-stability": "dev", - "prefer-stable": true, "require": { - "cloudinary/cloudinary_php": "dev-master", + "cloudinary/cloudinary_php": "~1.7", "google/recaptcha": "~1.1", - "projek-xyz/slim-plates": "~0.2", - "phpmailer/phpmailer": "^5.2", - "slim/slim": "~3.1", - "slim/flash": "~0.1", - "slim/pdo": "~1.9", - "vlucas/valitron": "~1.0" + "projek-xyz/slim-plates": "~0.2.2", + "phpmailer/phpmailer": "~5.2", + "slim/slim": "~3.8", + "slim/flash": "~0.2.0", + "slim/pdo": "~1.10", + "vlucas/valitron": "~1.4", + "vlucas/phpdotenv": "~2.4", + "php-http/curl-client": "^1.7" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" }, "autoload": { "psr-4": { @@ -21,5 +24,10 @@ "files": [ "app/src/helpers.php" ] + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "preferred-install": "dist" } } diff --git a/composer.lock b/composer.lock index c6abe7d..7b275b5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "b931613adf63a061d22a824a72791ca8", - "content-hash": "66fd3c3dbf0164578dc55b98478ba2e3", + "content-hash": "cc577845e5524a0b3d149dd4bddf5919", "packages": [ { "name": "cloudinary/cloudinary_php", - "version": "dev-master", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/cloudinary/cloudinary_php.git", - "reference": "94582b6bc7d6c5b97f9aae441d7d25e6fd93ef76" + "reference": "330b6b3f6fcb093a4f2345d5974a849e5f12e569" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cloudinary/cloudinary_php/zipball/94582b6bc7d6c5b97f9aae441d7d25e6fd93ef76", - "reference": "94582b6bc7d6c5b97f9aae441d7d25e6fd93ef76", + "url": "https://api.github.com/repos/cloudinary/cloudinary_php/zipball/330b6b3f6fcb093a4f2345d5974a849e5f12e569", + "reference": "330b6b3f6fcb093a4f2345d5974a849e5f12e569", "shasum": "" }, "require": { @@ -27,7 +26,7 @@ "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "4.7.*" + "phpunit/phpunit": "5.7.*" }, "type": "library", "autoload": { @@ -57,22 +56,74 @@ "image management", "sdk" ], - "time": "2016-03-22 14:54:00" + "time": "2017-04-03T08:28:38+00:00" + }, + { + "name": "clue/stream-filter", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/php-stream-filter.git", + "reference": "e3bf9415da163d9ad6701dccb407ed501ae69785" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/php-stream-filter/zipball/e3bf9415da163d9ad6701dccb407ed501ae69785", + "reference": "e3bf9415da163d9ad6701dccb407ed501ae69785", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\StreamFilter\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@lueck.tv" + } + ], + "description": "A simple and modern approach to stream filtering in PHP", + "homepage": "https://github.com/clue/php-stream-filter", + "keywords": [ + "bucket brigade", + "callback", + "filter", + "php_user_filter", + "stream", + "stream_filter_append", + "stream_filter_register" + ], + "time": "2015-11-08T23:41:30+00:00" }, { "name": "container-interop/container-interop", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/container-interop/container-interop.git", - "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", - "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", "shasum": "" }, + "require": { + "psr/container": "^1.0" + }, "type": "library", "autoload": { "psr-4": { @@ -84,27 +135,28 @@ "MIT" ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "time": "2014-12-30 15:22:37" + "homepage": "https://github.com/container-interop/container-interop", + "time": "2017-02-14T19:40:03+00:00" }, { "name": "google/recaptcha", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/google/recaptcha.git", - "reference": "2b7e00566afca82a38a1d3adb8e42c118006296e" + "reference": "5a56d15ca10a7b75158178752b2ad8f755eb4f78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/recaptcha/zipball/2b7e00566afca82a38a1d3adb8e42c118006296e", - "reference": "2b7e00566afca82a38a1d3adb8e42c118006296e", + "url": "https://api.github.com/repos/google/recaptcha/zipball/5a56d15ca10a7b75158178752b2ad8f755eb4f78", + "reference": "5a56d15ca10a7b75158178752b2ad8f755eb4f78", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "4.5.*" + "phpunit/phpunit": "^4.8" }, "type": "library", "extra": { @@ -129,24 +181,27 @@ "recaptcha", "spam" ], - "time": "2015-09-02 17:23:59" + "time": "2017-03-09T18:44:34+00:00" }, { "name": "league/plates", - "version": "3.1.1", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/thephpleague/plates.git", - "reference": "2d8569e9f140a70d6a05db38006926f7547cb802" + "reference": "b1684b6f127714497a0ef927ce42c0b44b45a8af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802", - "reference": "2d8569e9f140a70d6a05db38006926f7547cb802", + "url": "https://api.github.com/repos/thephpleague/plates/zipball/b1684b6f127714497a0ef927ce42c0b44b45a8af", + "reference": "b1684b6f127714497a0ef927ce42c0b44b45a8af", "shasum": "" }, + "require": { + "php": "^5.3 | ^7.0" + }, "require-dev": { - "mikey179/vfsstream": "~1.4.0", + "mikey179/vfsstream": "^1.4", "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~1.5" }, @@ -181,20 +236,20 @@ "templating", "views" ], - "time": "2015-07-09 02:14:40" + "time": "2016-12-28T00:14:17+00:00" }, { "name": "nikic/fast-route", - "version": "v0.6.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/nikic/FastRoute.git", - "reference": "31fa86924556b80735f98b294a7ffdfb26789f22" + "reference": "b5f95749071c82a8e0f58586987627054400cdf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22", - "reference": "31fa86924556b80735f98b294a7ffdfb26789f22", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/b5f95749071c82a8e0f58586987627054400cdf6", + "reference": "b5f95749071c82a8e0f58586987627054400cdf6", "shasum": "" }, "require": { @@ -224,95 +279,101 @@ "router", "routing" ], - "time": "2015-06-18 19:15:47" + "time": "2017-01-19T11:35:12+00:00" }, { - "name": "phpmailer/phpmailer", - "version": "v5.2.14", + "name": "php-http/curl-client", + "version": "v1.7.0", "source": { "type": "git", - "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "e774bc9152de85547336e22b8926189e582ece95" + "url": "https://github.com/php-http/curl-client.git", + "reference": "0972ad0d7d37032a52077a5cbe27cf370f2007d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e774bc9152de85547336e22b8926189e582ece95", - "reference": "e774bc9152de85547336e22b8926189e582ece95", + "url": "https://api.github.com/repos/php-http/curl-client/zipball/0972ad0d7d37032a52077a5cbe27cf370f2007d8", + "reference": "0972ad0d7d37032a52077a5cbe27cf370f2007d8", "shasum": "" }, "require": { - "php": ">=5.0.0" + "ext-curl": "*", + "php": "^5.5 || ^7.0", + "php-http/discovery": "^1.0", + "php-http/httplug": "^1.0", + "php-http/message": "^1.2", + "php-http/message-factory": "^1.0.2" }, - "require-dev": { - "phpdocumentor/phpdocumentor": "*", - "phpunit/phpunit": "4.7.*" + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0" }, - "suggest": { - "league/oauth2-client": "Needed for XOAUTH2 authentication", - "league/oauth2-google": "Needed for Gmail XOAUTH2" + "require-dev": { + "guzzlehttp/psr7": "^1.0", + "php-http/client-integration-tests": "^0.5.1", + "phpunit/phpunit": "^4.8.27", + "zendframework/zend-diactoros": "^1.0" }, "type": "library", "autoload": { - "classmap": [ - "class.phpmailer.php", - "class.phpmaileroauth.php", - "class.phpmaileroauthgoogle.php", - "class.smtp.php", - "class.pop3.php", - "extras/EasyPeasyICS.php", - "extras/ntlm_sasl_client.php" - ] + "psr-4": { + "Http\\Client\\Curl\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-2.1" + "MIT" ], "authors": [ { - "name": "Jim Jagielski", - "email": "jimjag@gmail.com" - }, - { - "name": "Marcus Bointon", - "email": "phpmailer@synchromedia.co.uk" - }, - { - "name": "Andy Prevost", - "email": "codeworxtech@users.sourceforge.net" - }, - { - "name": "Brent R. Matzelle" + "name": "Михаил Красильников", + "email": "m.krasilnikov@yandex.ru" } ], - "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "time": "2015-11-01 10:15:28" + "description": "cURL client for PHP-HTTP", + "homepage": "http://php-http.org", + "keywords": [ + "curl", + "http" + ], + "time": "2017-02-09T15:18:33+00:00" }, { - "name": "pimple/pimple", - "version": "v3.0.2", + "name": "php-http/discovery", + "version": "1.2.1", "source": { "type": "git", - "url": "https://github.com/silexphp/Pimple.git", - "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" + "url": "https://github.com/php-http/discovery.git", + "reference": "6b33475a3239439bc7ced287d0de0bb82e04d2f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", - "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "url": "https://api.github.com/repos/php-http/discovery/zipball/6b33475a3239439bc7ced287d0de0bb82e04d2f0", + "reference": "6b33475a3239439bc7ced287d0de0bb82e04d2f0", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^5.5 || ^7.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^2.0.2", + "php-http/httplug": "^1.0", + "php-http/message-factory": "^1.0", + "phpspec/phpspec": "^2.4", + "puli/composer-plugin": "1.0.0-beta10" + }, + "suggest": { + "php-http/message": "Allow to use Guzzle, Diactoros or Slim Framework factories", + "puli/composer-plugin": "Sets up Puli which is recommended for Discovery to work. Check http://docs.php-http.org/en/latest/discovery.html for more details." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "1.3-dev" } }, "autoload": { - "psr-0": { - "Pimple": "src/" + "psr-4": { + "Http\\Discovery\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -321,49 +382,55 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" } ], - "description": "Pimple, a simple Dependency Injection Container", - "homepage": "http://pimple.sensiolabs.org", + "description": "Finds installed HTTPlug implementations and PSR-7 message factories", + "homepage": "http://php-http.org", "keywords": [ - "container", - "dependency injection" + "adapter", + "client", + "discovery", + "factory", + "http", + "message", + "psr7" ], - "time": "2015-09-11 15:10:35" + "time": "2017-03-02T06:56:00+00:00" }, { - "name": "projek-xyz/slim-plates", - "version": "v0.2.1", + "name": "php-http/httplug", + "version": "v1.1.0", "source": { "type": "git", - "url": "https://github.com/projek-xyz/slim-plates.git", - "reference": "6b6d22ad0e35e6cd9e0d66f744f278f59acd5ac4" + "url": "https://github.com/php-http/httplug.git", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/projek-xyz/slim-plates/zipball/6b6d22ad0e35e6cd9e0d66f744f278f59acd5ac4", - "reference": "6b6d22ad0e35e6cd9e0d66f744f278f59acd5ac4", + "url": "https://api.github.com/repos/php-http/httplug/zipball/1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018", "shasum": "" }, "require": { - "league/plates": "~3.1.0", - "php": ">=5.5.0", - "slim/slim": "~3.0" + "php": ">=5.4", + "php-http/promise": "^1.0", + "psr/http-message": "^1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.2-dev" + "dev-master": "1.1-dev" } }, "autoload": { "psr-4": { - "Projek\\Slim\\": "src/" + "Http\\Client\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -372,49 +439,71 @@ ], "authors": [ { - "name": "Fery Wardiyanto", - "email": "hallo@feryardiant.me", - "homepage": "http://feryardiant.me" + "name": "Eric GELOEN", + "email": "geloen.eric@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" } ], - "description": "Slim Framework 3 view helper built on top of the Plates templating component", - "homepage": "http://www.projek.xyz/slim-plates", + "description": "HTTPlug, the HTTP client abstraction for PHP", + "homepage": "http://httplug.io", "keywords": [ - "framework", - "plates", - "slim", - "template", - "view" + "client", + "http" ], - "time": "2016-01-25 09:25:36" + "time": "2016-08-31T08:30:17+00:00" }, { - "name": "psr/http-message", - "version": "1.0", + "name": "php-http/message", + "version": "1.5.0", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + "url": "https://github.com/php-http/message.git", + "reference": "13df8c48f40ca7925303aa336f19be4b80984f01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "url": "https://api.github.com/repos/php-http/message/zipball/13df8c48f40ca7925303aa336f19be4b80984f01", + "reference": "13df8c48f40ca7925303aa336f19be4b80984f01", "shasum": "" }, "require": { - "php": ">=5.3.0" + "clue/stream-filter": "^1.3", + "php": ">=5.4", + "php-http/message-factory": "^1.0.2", + "psr/http-message": "^1.0" + }, + "require-dev": { + "akeneo/phpspec-skip-example-extension": "^1.0", + "coduo/phpspec-data-provider-extension": "^1.0", + "ext-zlib": "*", + "guzzlehttp/psr7": "^1.0", + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4", + "slim/slim": "^3.0", + "zendframework/zend-diactoros": "^1.0" + }, + "suggest": { + "ext-zlib": "Used with compressor/decompressor streams", + "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories", + "slim/slim": "Used with Slim Framework PSR-7 implementation", + "zendframework/zend-diactoros": "Used with Diactoros Factories" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.6-dev" } }, "autoload": { "psr-4": { - "Psr\\Http\\Message\\": "src/" - } + "Http\\Message\\": "src/" + }, + "files": [ + "src/filters.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -422,42 +511,46 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" } ], - "description": "Common interface for HTTP messages", + "description": "HTTP Message related tools", + "homepage": "http://php-http.org", "keywords": [ "http", - "http-message", - "psr", - "psr-7", - "request", - "response" + "message", + "psr-7" ], - "time": "2015-05-04 20:22:00" + "time": "2017-02-14T08:58:37+00:00" }, { - "name": "slim/flash", - "version": "0.1.0", + "name": "php-http/message-factory", + "version": "v1.0.2", "source": { "type": "git", - "url": "https://github.com/slimphp/Slim-Flash.git", - "reference": "1995ed53b77b8eeb67adf032de93c319f76aa5cd" + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim-Flash/zipball/1995ed53b77b8eeb67adf032de93c319f76aa5cd", - "reference": "1995ed53b77b8eeb67adf032de93c319f76aa5cd", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=5.4", + "psr/http-message": "^1.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, "autoload": { "psr-4": { - "Slim\\Flash\\": "src" + "Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -466,44 +559,48 @@ ], "authors": [ { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "http://joshlockhart.com" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" } ], - "description": "Slim Framework Flash message service provider", - "homepage": "http://slimframework.com", + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", "keywords": [ - "flash", - "framework", + "factory", + "http", "message", - "provider", - "slim" + "stream", + "uri" ], - "time": "2015-08-16 22:49:06" + "time": "2015-12-19T14:08:53+00:00" }, { - "name": "slim/pdo", - "version": "1.9.8", + "name": "php-http/promise", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/FaaPz/Slim-PDO.git", - "reference": "5f766ca63b8a8e45e7a27acaa3edadb1cf5e55a8" + "url": "https://github.com/php-http/promise.git", + "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FaaPz/Slim-PDO/zipball/5f766ca63b8a8e45e7a27acaa3edadb1cf5e55a8", - "reference": "5f766ca63b8a8e45e7a27acaa3edadb1cf5e55a8", + "url": "https://api.github.com/repos/php-http/promise/zipball/dc494cdc9d7160b9a09bd5573272195242ce7980", + "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980", "shasum": "" }, - "require": { - "ext-pdo": "*", - "php": ">=5.3.0" + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, "autoload": { "psr-4": { - "Slim\\PDO\\": "src/PDO/" + "Http\\Promise\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -512,113 +609,537 @@ ], "authors": [ { - "name": "Fabian de Laender", - "email": "fabian@faapz.nl", - "homepage": "http://faapz.nl", - "role": "Developer" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" } ], - "description": "PDO database library for Slim Framework", - "homepage": "https://github.com/FaaPz/Slim-PDO", + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", "keywords": [ - "database", - "framework", - "pdo", - "slim" + "promise" ], - "time": "2016-02-27 16:38:28" + "time": "2016-01-26T13:27:02+00:00" }, { - "name": "slim/slim", - "version": "3.3.0", + "name": "phpmailer/phpmailer", + "version": "v5.2.23", "source": { "type": "git", - "url": "https://github.com/slimphp/Slim.git", - "reference": "939f2e85d57508de9cff241d10091cd972f221c3" + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "7115df4a6f76281109ebe352900c42403b728bb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/939f2e85d57508de9cff241d10091cd972f221c3", - "reference": "939f2e85d57508de9cff241d10091cd972f221c3", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/7115df4a6f76281109ebe352900c42403b728bb4", + "reference": "7115df4a6f76281109ebe352900c42403b728bb4", "shasum": "" }, "require": { - "container-interop/container-interop": "^1.1", - "nikic/fast-route": "^0.6", - "php": ">=5.5.0", - "pimple/pimple": "^3.0", - "psr/http-message": "^1.0" + "php": ">=5.0.0" }, "require-dev": { - "phpunit/phpunit": "^4.0", - "squizlabs/php_codesniffer": "^2.5" + "doctrine/annotations": "1.2.*", + "jms/serializer": "0.16.*", + "phpdocumentor/phpdocumentor": "2.*", + "phpunit/phpunit": "4.8.*", + "symfony/debug": "2.8.*", + "symfony/filesystem": "2.8.*", + "symfony/translation": "2.8.*", + "symfony/yaml": "2.8.*", + "zendframework/zend-cache": "2.5.1", + "zendframework/zend-config": "2.5.1", + "zendframework/zend-eventmanager": "2.5.1", + "zendframework/zend-filter": "2.5.1", + "zendframework/zend-i18n": "2.5.1", + "zendframework/zend-json": "2.5.1", + "zendframework/zend-math": "2.5.1", + "zendframework/zend-serializer": "2.5.*", + "zendframework/zend-servicemanager": "2.5.*", + "zendframework/zend-stdlib": "2.5.1" + }, + "suggest": { + "league/oauth2-google": "Needed for Google XOAUTH2 authentication" }, "type": "library", "autoload": { - "psr-4": { - "Slim\\": "Slim" - } + "classmap": [ + "class.phpmailer.php", + "class.phpmaileroauth.php", + "class.phpmaileroauthgoogle.php", + "class.smtp.php", + "class.pop3.php", + "extras/EasyPeasyICS.php", + "extras/ntlm_sasl_client.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "LGPL-2.1" ], "authors": [ { - "name": "Rob Allen", - "email": "rob@akrabat.com", - "homepage": "http://akrabat.com" + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" }, { - "name": "Josh Lockhart", - "email": "hello@joshlockhart.com", - "homepage": "https://joshlockhart.com" + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" }, { - "name": "Gabriel Manricks", - "email": "gmanricks@me.com", - "homepage": "http://gabrielmanricks.com" + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" }, { - "name": "Andrew Smith", - "email": "a.smith@silentworks.co.uk", - "homepage": "http://silentworks.co.uk" + "name": "Brent R. Matzelle" } ], - "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", - "homepage": "http://slimframework.com", - "keywords": [ - "api", - "framework", - "micro", - "router" - ], - "time": "2016-03-10 21:37:40" + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "time": "2017-03-15T19:32:56+00:00" }, { - "name": "vlucas/valitron", - "version": "v1.2.5", + "name": "pimple/pimple", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/vlucas/valitron.git", - "reference": "bb181072f427c1ba2ec8b433a0c35b60e99e207e" + "url": "https://github.com/silexphp/Pimple.git", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/valitron/zipball/bb181072f427c1ba2ec8b433a0c35b60e99e207e", - "reference": "bb181072f427c1ba2ec8b433a0c35b60e99e207e", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", "shasum": "" }, "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" + "php": ">=5.3.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, "autoload": { "psr-0": { - "Valitron": "src/" + "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": "projek-xyz/slim-plates", + "version": "v0.2.2", + "source": { + "type": "git", + "url": "https://github.com/projek-xyz/slim-plates.git", + "reference": "b1d51dedcdc0b0b4e67ba48c45ddc74747914ad9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/projek-xyz/slim-plates/zipball/b1d51dedcdc0b0b4e67ba48c45ddc74747914ad9", + "reference": "b1d51dedcdc0b0b4e67ba48c45ddc74747914ad9", + "shasum": "" + }, + "require": { + "league/plates": "~3.1", + "php": ">=5.5.0", + "slim/slim": "~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2-dev" + } + }, + "autoload": { + "psr-4": { + "Projek\\Slim\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fery Wardiyanto", + "email": "hallo@feryardiant.me", + "homepage": "http://feryardiant.me" + } + ], + "description": "Slim Framework 3 view helper built on top of the Plates templating component", + "homepage": "http://www.projek.xyz/slim-plates", + "keywords": [ + "framework", + "plates", + "slim", + "template", + "view" + ], + "time": "2016-10-09T23:22:07+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "slim/flash", + "version": "0.2.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Flash.git", + "reference": "3c9a26b3163820acc48080336c504d0a3cac6f30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Flash/zipball/3c9a26b3163820acc48080336c504d0a3cac6f30", + "reference": "3c9a26b3163820acc48080336c504d0a3cac6f30", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Flash\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" + } + ], + "description": "Slim Framework Flash message service provider", + "homepage": "http://slimframework.com", + "keywords": [ + "flash", + "framework", + "message", + "provider", + "slim" + ], + "time": "2016-11-11T16:29:19+00:00" + }, + { + "name": "slim/pdo", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/FaaPz/Slim-PDO.git", + "reference": "9424e6d5f3737a71722ab1f868c1d3090b63287d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FaaPz/Slim-PDO/zipball/9424e6d5f3737a71722ab1f868c1d3090b63287d", + "reference": "9424e6d5f3737a71722ab1f868c1d3090b63287d", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\PDO\\": "src/PDO/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabian de Laender", + "email": "fabian@faapz.nl", + "homepage": "http://faapz.nl", + "role": "Developer" + } + ], + "description": "PDO database library for Slim Framework", + "homepage": "https://github.com/FaaPz/Slim-PDO", + "keywords": [ + "database", + "framework", + "pdo", + "slim" + ], + "time": "2016-08-14T11:42:49+00:00" + }, + { + "name": "slim/slim", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "5385302707530b2bccee1769613ad769859b826d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/5385302707530b2bccee1769613ad769859b826d", + "reference": "5385302707530b2bccee1769613ad769859b826d", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "^1.2", + "nikic/fast-route": "^1.0", + "php": ">=5.5.0", + "pimple/pimple": "^3.0", + "psr/container": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "time": "2017-03-19T17:55:20+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause-Attribution" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2016-09-01T10:05:43+00:00" + }, + { + "name": "vlucas/valitron", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/valitron.git", + "reference": "b33c79116260637337187b7125f955ae26d306cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/valitron/zipball/b33c79116260637337187b7125f955ae26d306cc", + "reference": "b33c79116260637337187b7125f955ae26d306cc", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Valitron": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -627,27 +1148,1142 @@ ], "authors": [ { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Simple, elegant, stand-alone validation library with NO dependencies", + "homepage": "http://github.com/vlucas/valitron", + "keywords": [ + "valid", + "validation", + "validator" + ], + "time": "2017-02-23T08:31:59+00:00" + } + ], + "packages-dev": [ + { + "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": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27T11:43:31+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30T07:12:33+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-11-25T06:54:22+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2017-03-02T20:05:34+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06T15:47:00+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2016-10-03T07:40:28+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-02-27T10:12:30+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.35", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87", + "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-02-06T05:18:07+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02T06:51:40+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Simple, elegant, stand-alone validation library with NO dependencies", - "homepage": "http://github.com/vlucas/valitron", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "valid", - "validation", - "validator" + "diff" + ], + "time": "2015-12-08T07:14:41+00:00" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18T05:49:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17T09:04:28+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-10-03T07:41:43+00:00" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21T13:59:46+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/acec26fcf7f3031e094e910b94b002fa53d4e4d6", + "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/console": "~2.8|~3.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "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 Yaml Component", + "homepage": "https://symfony.com", + "time": "2017-05-01T14:55:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" ], - "time": "2016-03-15 21:14:19" + "time": "2016-11-23T20:04:58+00:00" } ], - "packages-dev": [], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "cloudinary/cloudinary_php": 20 - }, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": [], diff --git a/index.php b/index.php new file mode 100644 index 0000000..b4a42ba --- /dev/null +++ b/index.php @@ -0,0 +1,33 @@ +run(); diff --git a/www/index.php b/www/index.php deleted file mode 100644 index f2d7771..0000000 --- a/www/index.php +++ /dev/null @@ -1,21 +0,0 @@ -run();