From 5cd2e21e07c0573e6b59a00198699f673def10f4 Mon Sep 17 00:00:00 2001 From: Armen Markossyan Date: Fri, 2 May 2014 23:47:08 +0600 Subject: [PATCH 01/83] Fix #217 --- PHPCI/Plugin/PhpLoc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Plugin/PhpLoc.php b/PHPCI/Plugin/PhpLoc.php index 000b82cc..a00e6668 100644 --- a/PHPCI/Plugin/PhpLoc.php +++ b/PHPCI/Plugin/PhpLoc.php @@ -68,7 +68,7 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin return false; } - $success = $this->phpci->executeCommand($phploc . ' %s "%s"', $ignore, $this->phpci->buildPath); + $success = $this->phpci->executeCommand($phploc . ' %s "%s"', $ignore, $this->directory); $output = $this->phpci->getLastOutput(); if (preg_match_all('/\((LOC|CLOC|NCLOC|LLOC)\)\s+([0-9]+)/', $output, $matches)) { From 067aa858760a1ad2f6ffef7b4c41604c95e5e136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jari=20Ylim=C3=A4inen?= Date: Fri, 2 May 2014 22:58:22 +0300 Subject: [PATCH 02/83] Interpolate PHPUnit arguments --- PHPCI/Plugin/PhpUnit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Plugin/PhpUnit.php b/PHPCI/Plugin/PhpUnit.php index 16de7aa0..76f321b1 100755 --- a/PHPCI/Plugin/PhpUnit.php +++ b/PHPCI/Plugin/PhpUnit.php @@ -101,7 +101,7 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin } if (isset($options['args'])) { - $this->args = $options['args']; + $this->args = $this->phpci->interpolate($options['args']); } if (isset($options['path'])) { From 77daef3a5fe6a3438fd2863fb1b67758282ed1fd Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Tue, 6 May 2014 16:43:47 +0100 Subject: [PATCH 03/83] Fixing daemonise mode, forcing RunCommand to only get one build at a time when running under daemon mode --- PHPCI/Command/DaemoniseCommand.php | 1 + PHPCI/Command/RunCommand.php | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/PHPCI/Command/DaemoniseCommand.php b/PHPCI/Command/DaemoniseCommand.php index f8cbc45b..b4d0295c 100644 --- a/PHPCI/Command/DaemoniseCommand.php +++ b/PHPCI/Command/DaemoniseCommand.php @@ -76,6 +76,7 @@ class DaemoniseCommand extends Command $this->run = true; $this->sleep = 0; $runner = new RunCommand($this->logger); + $runner->setBaxBuilds(1); $emptyInput = new ArgvInput(array()); diff --git a/PHPCI/Command/RunCommand.php b/PHPCI/Command/RunCommand.php index 318f9247..dc64aef9 100644 --- a/PHPCI/Command/RunCommand.php +++ b/PHPCI/Command/RunCommand.php @@ -42,6 +42,11 @@ class RunCommand extends Command */ protected $logger; + /** + * @var int + */ + protected $maxBuilds = null; + /** * @param \Monolog\Logger $logger * @param string $name @@ -52,7 +57,6 @@ class RunCommand extends Command $this->logger = $logger; } - protected function configure() { $this @@ -69,7 +73,7 @@ class RunCommand extends Command // For verbose mode we want to output all informational and above // messages to the symphony output interface. - if ($input->getOption('verbose')) { + if ($input->hasOption('verbose')) { $this->logger->pushHandler( new OutputLogHandler($this->output, Logger::INFO) ); @@ -79,7 +83,7 @@ class RunCommand extends Command $this->logger->addInfo("Finding builds to process"); $store = Factory::getStore('Build'); - $result = $store->getByStatus(0); + $result = $store->getByStatus(0, $this->maxBuilds); $this->logger->addInfo(sprintf("Found %d builds", count($result['items']))); $builds = 0; @@ -113,4 +117,9 @@ class RunCommand extends Command return $builds; } + + public function setBaxBuilds($numBuilds) + { + $this->maxBuilds = (int)$numBuilds; + } } From b9397414c38dbf3e80d7ff8f94f7f743f86a0a61 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Tue, 6 May 2014 16:44:23 +0100 Subject: [PATCH 04/83] Enable setting config file path via env rather than assuming PHPCI/config.yml (both work) --- bootstrap.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index ee819c49..02e8c820 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -33,10 +33,24 @@ $autoload = function ($class) { spl_autoload_register($autoload, true, true); -if (!file_exists(dirname(__FILE__) . '/PHPCI/config.yml') && (!defined('PHPCI_IS_CONSOLE') || !PHPCI_IS_CONSOLE)) { +// If the PHPCI config file is not where we expect it, try looking in +// env for an alternative config path. +$configFile = dirname(__FILE__) . '/PHPCI/config.yml'; + +if (!file_exists($configFile)) { + $configEnv = getenv('phpci_config_file'); + + if (!empty($configEnv)) { + $configFile = $configEnv; + } +} + +// If we don't have a config file at all, fail at this point and tell the user to install: +if (!file_exists($configFile) && (!defined('PHPCI_IS_CONSOLE') || !PHPCI_IS_CONSOLE)) { die('PHPCI has not yet been installed - Please use the command ./console phpci:install to install it.'); } +// If composer has not been run, fail at this point and tell the user to install: if (!file_exists(dirname(__FILE__) . '/vendor/autoload.php') && defined('PHPCI_IS_CONSOLE') && PHPCI_IS_CONSOLE) { file_put_contents('php://stderr', 'Please install PHPCI with "composer install" before using console'); exit(1); @@ -54,9 +68,7 @@ $conf['b8']['app']['namespace'] = 'PHPCI'; $conf['b8']['app']['default_controller'] = 'Home'; $conf['b8']['view']['path'] = dirname(__FILE__) . '/PHPCI/View/'; -if (file_exists(dirname(__FILE__) . '/PHPCI/config.yml')) { - $config = new b8\Config($conf); - $config->loadYaml(dirname(__FILE__) . '/PHPCI/config.yml'); -} +$config = new b8\Config($conf); +$config->loadYaml($configFile); require_once(dirname(__FILE__) . '/vars.php'); From 9eefc7bf8ec4975e3401953a61007f21d957e615 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 7 May 2014 10:20:21 +0100 Subject: [PATCH 05/83] Making phpunit plugin log the TAP string in the event it fails to process it. --- PHPCI/Plugin/PhpUnit.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/PHPCI/Plugin/PhpUnit.php b/PHPCI/Plugin/PhpUnit.php index 16de7aa0..327e41f3 100755 --- a/PHPCI/Plugin/PhpUnit.php +++ b/PHPCI/Plugin/PhpUnit.php @@ -132,9 +132,16 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin $success &= $this->runDir($this->directory); } - $output = $this->phpci->getLastOutput(); - $tapParser = new TapParser($output); - $output = $tapParser->parse(); + $tapString = $this->phpci->getLastOutput(); + + try { + $tapParser = new TapParser($tapString); + $output = $tapParser->parse(); + } catch (\Exception $ex) { + $this->phpci->logFailure($tapString); + throw $ex; + } + $failures = $tapParser->getTotalFailures(); $this->build->storeMeta('phpunit-errors', $failures); From 033301682858c796924169671f7ded6432c78dee Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 7 May 2014 16:09:56 +0100 Subject: [PATCH 06/83] Converting build meta to use longtext instead of text, for builds with a lot of errors. --- PHPCI/Model/Base/BuildMetaBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Model/Base/BuildMetaBase.php b/PHPCI/Model/Base/BuildMetaBase.php index b7f85490..fc9183b2 100644 --- a/PHPCI/Model/Base/BuildMetaBase.php +++ b/PHPCI/Model/Base/BuildMetaBase.php @@ -98,7 +98,7 @@ class BuildMetaBase extends Model 'default' => null, ), 'meta_value' => array( - 'type' => 'text', + 'type' => 'longtext', 'nullable' => true, 'default' => null, ), From b1885a07fd3a25c962db4cb1c472d97f550dccd1 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 12:16:09 +0000 Subject: [PATCH 07/83] Fixing bootstrap for ./console phpci:install --- bootstrap.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bootstrap.php b/bootstrap.php index 02e8c820..2a271503 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -69,6 +69,9 @@ $conf['b8']['app']['default_controller'] = 'Home'; $conf['b8']['view']['path'] = dirname(__FILE__) . '/PHPCI/View/'; $config = new b8\Config($conf); -$config->loadYaml($configFile); + +if (file_exists($configFile)) { + $config->loadYaml($configFile); +} require_once(dirname(__FILE__) . '/vars.php'); From 43ce5554a60c56f949d92eed4056e0bf3072d39c Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 16:02:24 +0000 Subject: [PATCH 08/83] Adding PHP Docblock Checker plugin --- PHPCI/Plugin/PhpDocblockChecker.php | 138 ++++++++++++++++++ phpci.yml | 2 + public/assets/js/build-plugins/phpdoccheck.js | 78 ++++++++++ public/assets/js/build-plugins/warnings.js | 5 +- 4 files changed, 221 insertions(+), 2 deletions(-) create mode 100755 PHPCI/Plugin/PhpDocblockChecker.php create mode 100644 public/assets/js/build-plugins/phpdoccheck.js diff --git a/PHPCI/Plugin/PhpDocblockChecker.php b/PHPCI/Plugin/PhpDocblockChecker.php new file mode 100755 index 00000000..b41b8434 --- /dev/null +++ b/PHPCI/Plugin/PhpDocblockChecker.php @@ -0,0 +1,138 @@ + +* @package PHPCI +* @subpackage Plugins +*/ +class PhpDocblockChecker implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin +{ + /** + * @var \PHPCI\Builder + */ + protected $phpci; + + /** + * @var \PHPCI\Model\Build + */ + protected $build; + + /** + * @var string Based on the assumption the root may not hold the code to be + * tested, extends the build path. + */ + protected $path; + + /** + * @var array - paths to ignore + */ + protected $ignore; + + protected $skipClasses = false; + protected $skipMethods = false; + + public static function canExecute($stage, Builder $builder, Build $build) + { + if ($stage == 'test') { + return true; + } + + return false; + } + + + public function __construct(Builder $phpci, Build $build, array $options = array()) + { + $this->phpci = $phpci; + $this->build = $build; + $this->ignore = $phpci->ignore; + $this->path = ''; + $this->allowed_warnings = 0; + + if (isset($options['zero_config']) && $options['zero_config']) { + $this->allowed_warnings = -1; + } + + if (array_key_exists('skip_classes', $options)) { + $this->skipClasses = true; + } + + if (array_key_exists('skip_methods', $options)) { + $this->skipMethods = true; + } + + if (!empty($options['path'])) { + $this->path = $options['path']; + } + + if (array_key_exists('allowed_warnings', $options)) { + $this->allowed_warnings = (int)$options['allowed_warnings']; + } + } + + /** + * Runs PHP Mess Detector in a specified directory. + */ + public function execute() + { + $ignore = ''; + if (count($this->ignore)) { + $ignore = ' --exclude="' . implode(',', $this->ignore) . '"'; + } + + var_dump($ignore); + + $checker = $this->phpci->findBinary('phpdoccheck'); + + if (!$checker) { + $this->phpci->logFailure('Could not find phpdoccheck.'); + return false; + } + + $path = $this->phpci->buildPath . $this->path; + + $cmd = $checker . ' --json --directory="%s"%s%s%s'; + + // Disable exec output logging, as we don't want the XML report in the log: + $this->phpci->logExecOutput(false); + + // Run checker: + $this->phpci->executeCommand( + $cmd, + $path, + $ignore, + ($this->skipClasses ? ' --skip-classes' : ''), + ($this->skipMethods ? ' --skip-methods' : '') + ); + + // Re-enable exec output logging: + $this->phpci->logExecOutput(true); + + $output = json_decode($this->phpci->getLastOutput()); + $errors = count($output); + $success = true; + + $this->build->storeMeta('phpdoccheck-warnings', $errors); + $this->build->storeMeta('phpdoccheck-data', $output); + + if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) { + $success = false; + } + + return $success; + } +} diff --git a/phpci.yml b/phpci.yml index 9dda1fa4..24121476 100644 --- a/phpci.yml +++ b/phpci.yml @@ -17,6 +17,8 @@ test: standard: "PSR2" php_loc: php_unit: + php_docblock_checker: + allowed_warnings: -1 # Allow unlimited warnings for now. failure: email: diff --git a/public/assets/js/build-plugins/phpdoccheck.js b/public/assets/js/build-plugins/phpdoccheck.js new file mode 100644 index 00000000..89d8b449 --- /dev/null +++ b/public/assets/js/build-plugins/phpdoccheck.js @@ -0,0 +1,78 @@ +var phpdoccheckPlugin = PHPCI.UiPlugin.extend({ + id: 'build-phpdoccheck-warnings', + css: 'col-lg-12 col-md-12 col-sm-12 col-xs-12', + title: 'PHP Docblock Checker', + lastData: null, + displayOnUpdate: false, + box: true, + + register: function() { + var self = this; + var query = PHPCI.registerQuery('phpdoccheck-data', -1, {key: 'phpdoccheck-data'}) + + $(window).on('phpdoccheck-data', function(data) { + self.onUpdate(data); + }); + + $(window).on('build-updated', function(data) { + if (data.queryData.status > 1) { + self.displayOnUpdate = true; + query(); + } + }); + }, + + render: function() { + + return $('' + + '' + + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + '
TypeFileLineClassMethod
'); + }, + + onUpdate: function(e) { + if (this.lastData && this.lastData[0]) { + return; + } + + this.lastData = e.queryData; + + var errors = this.lastData[0].meta_value; + var tbody = $('#phpdoccheck-data tbody'); + tbody.empty(); + + for (var i in errors) { + var file = errors[i].file; + + if (PHPCI.fileLinkTemplate) { + var fileLink = PHPCI.fileLinkTemplate.replace('{FILE}', file); + fileLink = fileLink.replace('{LINE}', errors[i].line); + + file = '' + file + ''; + } + + var row = $('' + + ''+errors[i].type+'' + + ''+file+'' + + ''+errors[i].line+'' + + ''+errors[i].class+'' + + ''+errors[i].method+''); + + if (errors[i].type == 'method') { + row.addClass('danger'); + } else { + row.addClass('warning'); + } + + tbody.append(row); + } + } +}); + +PHPCI.registerPlugin(new phpdoccheckPlugin()); diff --git a/public/assets/js/build-plugins/warnings.js b/public/assets/js/build-plugins/warnings.js index cc2db78f..70d2b4b2 100644 --- a/public/assets/js/build-plugins/warnings.js +++ b/public/assets/js/build-plugins/warnings.js @@ -7,7 +7,8 @@ var warningsPlugin = PHPCI.UiPlugin.extend({ 'phpcs-warnings': 'PHPCS Warnings', 'phpcs-errors': 'PHPCS Errors', 'phplint-errors': 'PHPLint Errors', - 'phpunit-errors': 'PHPUnit Errors' + 'phpunit-errors': 'PHPUnit Errors', + 'phpdoccheck-warnings': 'PHP Docblock Checker Warnings' }, data: {}, displayOnUpdate: false, @@ -20,7 +21,7 @@ var warningsPlugin = PHPCI.UiPlugin.extend({ queries.push(PHPCI.registerQuery(key, -1, {num_builds: 10, key: key})); } - $(window).on('phpmd-warnings phpcs-warnings phpcs-errors phplint-errors phpunit-errors', function(data) { + $(window).on('phpmd-warnings phpcs-warnings phpcs-errors phplint-errors phpunit-errors phpdoccheck-errors', function(data) { self.onUpdate(data); }); From e297f60273c4eb43f01b1ba75b5cd49e892ec385 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 16:02:51 +0000 Subject: [PATCH 09/83] Fixing zero config ignore setting --- PHPCI/Model/Build.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Model/Build.php b/PHPCI/Model/Build.php index e8b8cd5a..174126fa 100644 --- a/PHPCI/Model/Build.php +++ b/PHPCI/Model/Build.php @@ -122,7 +122,7 @@ class Build extends BuildBase $config = array( 'build_settings' => array( 'ignore' => array( - 'vendor/', + 'vendor', ) ) ); From b381b7864ab86e2776695e2d62b43e6db0c4816e Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 16:03:17 +0000 Subject: [PATCH 10/83] Updating license year --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 7d8d2f31..60a3727d 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2013, Block 8 Limited +Copyright (c) 2014, Block 8 Limited All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From b950e4d66215af02f7b5b16c271a195ae2913aa1 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 16:03:29 +0000 Subject: [PATCH 11/83] Updating license year --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 60a3727d..1df52b9c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2014, Block 8 Limited +Copyright (c) 2013-2014, Block 8 Limited All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From efd207377948fe840f5d5e28fe314a17cdb12b6f Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 16:04:37 +0000 Subject: [PATCH 12/83] Updating composer.json --- composer.json | 1 + composer.lock | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index a6dec175..6cb24ba1 100644 --- a/composer.json +++ b/composer.json @@ -43,6 +43,7 @@ }, "suggest": { + "block8/php-docblock-checker": "PHP Docblock Checker", "phpmd/phpmd": "PHP Mess Detector", "sebastian/phpcpd": "PHP Copy/Paste Detector", "squizlabs/php_codesniffer": "PHP Code Sniffer", diff --git a/composer.lock b/composer.lock index 1110c4b5..d8f78d4c 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "d6834b50e3ea80f4c6f0a05707d0e5f1", + "hash": "0692857385ac27090b3000cbc680ced8", "packages": [ { "name": "block8/b8framework", @@ -247,25 +247,28 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v5.1.0", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "748c01c1144713ac0118396935d10b6ceec91b68" + "reference": "043e336b871f17a117f76ef8e190eddfc04c8d48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/748c01c1144713ac0118396935d10b6ceec91b68", - "reference": "748c01c1144713ac0118396935d10b6ceec91b68", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/043e336b871f17a117f76ef8e190eddfc04c8d48", + "reference": "043e336b871f17a117f76ef8e190eddfc04c8d48", "shasum": "" }, "require": { "php": ">=5.2.4" }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "5.2-dev" } }, "autoload": { @@ -294,7 +297,7 @@ "mail", "mailer" ], - "time": "2014-03-18 09:03:27" + "time": "2014-05-08 08:11:19" }, { "name": "symfony/console", From 0654bcccee396cc39dc600c48d9a3e7045597f4b Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 8 May 2014 17:59:08 +0000 Subject: [PATCH 13/83] Adding edit profile (and change password) option for users. --- PHPCI/Controller/UserController.php | 57 ++++++++++++++++++++++++++++- PHPCI/View/User/profile.phtml | 15 ++++++++ PHPCI/View/layout.phtml | 18 ++++++++- 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 PHPCI/View/User/profile.phtml diff --git a/PHPCI/Controller/UserController.php b/PHPCI/Controller/UserController.php index c8fade0c..817cb5e8 100644 --- a/PHPCI/Controller/UserController.php +++ b/PHPCI/Controller/UserController.php @@ -29,7 +29,7 @@ class UserController extends Controller public function init() { - $this->userStore = b8\Store\Factory::getStore('User'); + $this->userStore = b8\Store\Factory::getStore('User'); } /** @@ -45,6 +45,61 @@ class UserController extends Controller return $this->view->render(); } + public function profile() + { + $user = $_SESSION['user']; + $values = $user->getDataArray(); + + if ($this->request->getMethod() == 'POST') { + $values = $this->getParams(); + + if (!empty($values['password'])) { + $values['hash'] = password_hash($values['password'], PASSWORD_DEFAULT); + } + + $this->view->updated = true; + + $user->setValues($values); + $_SESSION['user'] = $this->userStore->save($user); + } + + $form = new Form(); + $form->setAction(PHPCI_URL.'user/profile'); + $form->setMethod('POST'); + + $name = new Form\Element\Text('name'); + $name->setClass('form-control'); + $name->setContainerClass('form-group'); + $name->setLabel('Name'); + $name->setRequired(true); + $form->addField($name); + + $email = new Form\Element\Email('email'); + $email->setClass('form-control'); + $email->setContainerClass('form-group'); + $email->setLabel('Email Address'); + $email->setRequired(true); + $form->addField($email); + + $password = new Form\Element\Password('password'); + $password->setClass('form-control'); + $password->setContainerClass('form-group'); + $password->setLabel('Password (leave blank if you don\'t want to change it)'); + $password->setRequired(false); + $form->addField($password); + + $submit = new Form\Element\Submit(); + $submit->setClass('btn btn-success'); + $submit->setValue('Save »'); + $form->addField($submit); + + $form->setValues($values); + + $this->view->form = $form; + + return $this->view->render(); + } + /** * Add a user - handles both form and processing. */ diff --git a/PHPCI/View/User/profile.phtml b/PHPCI/View/User/profile.phtml new file mode 100644 index 00000000..5e006738 --- /dev/null +++ b/PHPCI/View/User/profile.phtml @@ -0,0 +1,15 @@ +

User()->getName(); ?>

+ + +

Your details have been updated.

+ + +
+
+

Update your details

+
+
+ +
+
+ diff --git a/PHPCI/View/layout.phtml b/PHPCI/View/layout.phtml index 58b78cc2..ed3e539e 100644 --- a/PHPCI/View/layout.phtml +++ b/PHPCI/View/layout.phtml @@ -37,13 +37,27 @@