17 |
18 |
--------------------------------------------------------------------------------
/tests/api_test/delete.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2014
9 | * @license /license.txt
10 | */
11 | if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
12 | echo 'Working';
13 | } else {
14 | echo 'ERROR: not a DELETE Request';
15 | }
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | ## Unit Testing for Flight-MVC
2 |
3 | All of the code for the MVC extension is tested using phpUnit. For the PdoConn class, there is a `unit_test.db` sqlite database in the `/data/sqlite` subfolder. This database is used for some read/write tests. If you find that the tests are failing, make sure that the directory that the database is in is writeable.
4 |
--------------------------------------------------------------------------------
/application/view/404.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014
10 | * @license /license.txt
11 | */
12 | ?>
13 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/cli/templates/model.txt:
--------------------------------------------------------------------------------
1 |
14 | */
15 | namespace fmvc\application\model{SUBDIR_NAME};
16 |
17 | class {MODEL_NAME}
18 | {
19 | public function __construct()
20 | {
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # PACKAGES #
2 | *.phar
3 | *.lock
4 | *.com
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 |
10 | # OS Files #
11 | .DS_Store
12 | .DS_Store?
13 | ._*
14 | .Spotlight-V100
15 | .Trashes
16 | ehthumbs.db
17 | Thumbs.db
18 | .idea/*
19 |
20 | # LOGS / DATABASES #
21 | *.sqlite
22 | *.log
23 | error_log/*
24 | temp/*
25 |
26 | # APP SPECIFIC #
27 | web/scripts/jquery/*
28 | libraries/*
29 | cgi-bin/*
30 | build.xml
31 | tests/temp/*
32 | tests/coverage/*
33 | web.config
34 | php.ini
--------------------------------------------------------------------------------
/docs/debugging.md:
--------------------------------------------------------------------------------
1 | #Debugging
2 |
3 | There is a global function called `debug()` that can be called. It will provide an easily readable view of whatever array / object you are trying to view
4 |
5 | Additionally, there are a few commands in the default `Debug` controller like:
6 | * `this`: shows the debug dump of the Controller object
7 | * `info`: shows `phpinfo()
8 | * `config`: show the debug dump of the config object
9 |
10 | These commands do not work in production mode, but it is highly recommended to delete them from the controller or delete the controller entirely if they are not needed to protect application security.
11 |
12 |
--------------------------------------------------------------------------------
/docs/windows_authentication.md:
--------------------------------------------------------------------------------
1 | #Windows Authentication
2 | Flight-MVC has optional Windows authentication built into the router. To enable,
3 | set the configuration variable for using Windows authentication to `true`.
4 |
5 | Note that you will also need to enable Windows Authentication and disable anonymous
6 | authentication in IIS.
7 |
8 | Once you have enabled Windows authentication, you can also enter a domain name (with
9 | a trailing backslash) in the domain config variable to strip the domain name from
10 | the user name if desired.
11 |
12 | To add in more processing when the Windows authentication check takes place, modify
13 | the `core\routes.php` file in the designate area to make it work for you.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "minimum-stability": "dev",
3 | "name": "flight-base-app",
4 | "version": "0.1.0",
5 | "config": {
6 | "vendor-dir": "libraries"
7 | },
8 |
9 | "require": {
10 | "mikecao/flight": "dev-master",
11 | "erusev/parsedown": "dev-master"
12 | },
13 |
14 | "require-dev": {
15 | "phing/phing": "2.*",
16 | "squizlabs/php_codesniffer": "2.*",
17 | "phpunit/phpunit": "5.*",
18 | "sebastian/phpcpd": "3.*",
19 | "phpmd/phpmd" : "dev-master"
20 | },
21 |
22 | "autoload": {
23 | "psr-4": {
24 | "fmvc\\core\\": "core",
25 | "fmvc\\application\\": "application"
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/config/environment.php:
--------------------------------------------------------------------------------
1 |
19 | * @copyright 2013
20 | * @license /license.txt
21 | */
22 |
23 | // Define the running mode if desired
24 | // If set to null, the auto-detector will take over
25 | define('APP_ENVIRONMENT', null);
--------------------------------------------------------------------------------
/docs/views.md:
--------------------------------------------------------------------------------
1 | #Using Views
2 |
3 | Most of the documentation for views can be found by looking at the documentation for Flight at [http://flightphp.com]. The main thing to understand about how this extension implements views is that the views are simply organized into the `application/views` folder. The bootstrapper sets the default view path to this directory.
4 |
5 | I recommend adding a subfolder for each controller to keep things tidy.
6 |
7 | You can call views in a subfolder as follows:
8 |
9 | ```
10 | //let's say we want to render the application/views/home/index.php view file.
11 |
12 | \Flight::render('home/index', array());
13 |
14 | ```
15 |
16 | Layouts work the same way as views as far as directory and file structure are involved. The Flight documentation explains how layouts/templates are implemented.
17 |
--------------------------------------------------------------------------------
/web/index.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014
12 | * @license /license.txt
13 | */
14 |
15 | // Load the environment configuration file
16 | require_once dirname(__DIR__) . '/config/environment.php';
17 |
18 | // include autoloader files
19 | require_once dirname(__DIR__) . '/libraries/autoload.php';
20 |
21 | // include global functions
22 | require_once dirname(__DIR__) . '/core/functions/global_functions.php';
23 |
24 | // Load the environment based configuration
25 | require_once dirname(__DIR__) . '/config/' .setEnvironment(APP_ENVIRONMENT). '.php';
26 |
27 | // load the bootstrap file
28 | require_once dirname(__DIR__) . '/core/bootstrap.php';
29 |
30 | // here we go!
31 | Flight::start();
--------------------------------------------------------------------------------
/docs/models.md:
--------------------------------------------------------------------------------
1 | #Using Models
2 |
3 | Models are where most of the work should be getting done in your application. This is where the processing takes place and then the results are passed back to the controller and then rendered to a view.
4 |
5 | All models in this extension can pretty well stand on their own and bring in dependencies as needed. The only requirement is adding an appropriate namespace based on the location of the file which at the simplest level will be `application\model`. You can add more subfolders for organization as needed, just be sure to include the appropriate namespace
6 |
7 | You are free to handle your models however you see fit, but the best result will be found in using solid coding practices and observing the concepts of dependency injection, writing testable code, etc. Volumes have been written on these subjects, and you will hopefully find in a study of this extension's code, that every effort was made to develop using these best practices.
--------------------------------------------------------------------------------
/cli/templates/controller.txt:
--------------------------------------------------------------------------------
1 |
12 | */
13 | namespace fmvc\application\controller{SUBDIR_NAME};
14 |
15 | class {MODEL_NAME} extends \fmvc\core\lib\Controller
16 | {
17 | /**
18 | * Constructor: Dependencies are picked up from routes.php The default
19 | * Dependencies sent to the controller are Config and Input, which are then
20 | * passed through to the parent constructor
21 | * @param array $deps dependencies
22 | * @param array $params parameters passed via the uri
23 | */
24 | public function __construct($deps, $params)
25 | {
26 | parent::__construct($deps, $params);
27 |
28 | }
29 |
30 | public function index()
31 | {
32 | echo 'Welcome to the {MODEL_NAME} controller';
33 | }
34 | }
--------------------------------------------------------------------------------
/application/controller/Home.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2014
9 | * @license /license.txt
10 | */
11 | namespace fmvc\application\controller;
12 |
13 | class Home extends \fmvc\core\lib\Controller
14 | {
15 | /**
16 | * Constructor: Dependencies are picked up from routes.php The default
17 | * Dependencies sent to the controller are Config and Input, which are then
18 | * passed through to the parent constructor
19 | * @param array $deps dependencies
20 | * @param array $params parameters passed via the uri
21 | */
22 | public function __construct($deps, $params)
23 | {
24 | parent::__construct($deps, $params);
25 | }
26 |
27 | /**
28 | * Main Menu, Home Page
29 | */
30 | public function index()
31 | {
32 |
33 | \Flight::render('home/index', array('html_head' => $this->head->head()));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/input_filtering.md:
--------------------------------------------------------------------------------
1 | #Input Filtering
2 |
3 | The `core\helper\Filter` class includes several static methods that can be useful for filtering data that comes into the application. Many of the filters are just simple implementations of built in methods like `ctype`, but as filtering in web applications is an ever evolving process, using these static wrapper methods, you can adapt your filtering requirements as time goes on by simply updating the static method code rather than endlessly hunt for filtering logic throughout the application.
4 |
5 | The following filters are built into the class:
6 | * filename: by default, accepts alphanumerics plus periods and underscores
7 | * integer
8 | * numeric
9 | * alphanumeric
10 | * alpha
11 | * email (implements the Email type on filter_var)
12 | * boolean
13 | * pageName: by default accepts alphanumeric plus underscore
14 | * databaseField: by default, accepts alphanumerics plus periods and underscores
15 | * checkDateIsValid: this one needs simplification work, I know, but it is functional for now. I am sure there are better ways
16 |
17 | Usage:
18 | `Filter::numeric($data)`
19 |
20 | Returns `true` or `false` depending on if the data is valid.
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/logger.md:
--------------------------------------------------------------------------------
1 | #Using the Logger
2 |
3 | The logger is meant to be very simple and intended to implement basic logging functions. The logger class is not loaded by default into the Controller class, and needs to be instantiated.
4 |
5 | ##Configuring
6 | The config object must be passed into the logger.
7 |
8 | The configuration file for each environment contains a `$config['error_log_path']` element which is set to the `error_log/`; directory by default.
9 |
10 | By default, the logger has 4 logging levels:
11 | * event
12 | * notice
13 | * warning
14 | * error
15 |
16 | These levels are setup in the `core/helper/Logger.php` class file in the $foo->levels property of the class. You can modify these logging levels as desired by changing the contents of the array.
17 |
18 | ## Using the logger:
19 | Dynamic methods are used to log events. If you want to log a warning, for example, then you would use the `$foo->warning()` method. The dynamic logger methods accept 2 parameters. The first parameter is the message or description of the log event and the second parameter is any data you want to capture with the log event.
20 |
21 | The logger stores logged events in a text file in the directory that is specified. The name of the file will correspond to the log level like `warning.txt`, `notice.txt`, and so forth.
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Andrew Podner
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 | NOTE: This license applies only to the code as developed by Andrew Podner. All
24 | other software is licensed as per the license specified by the original developer.
--------------------------------------------------------------------------------
/application/view/docs/index.php:
--------------------------------------------------------------------------------
1 |
10 | * @copyright 2013
11 | * @license /license.txt
12 | */
13 | ?>
14 |
15 |
16 | =$html_head?>
17 |
18 |
19 |
";
52 | debug($this);
53 | } else {
54 | echo 'DISABLED';
55 | }
56 | }
57 |
58 | /**
59 | * Debug dump of the Config Object (not in production)
60 | * DELETE THIS METHOD IF YOU DON'T NEED IT
61 | */
62 | public function config()
63 | {
64 | echo "Current Environment: " . \Flight::config()->item('environment') . " ";
65 | if (\Flight::config()->item('environment') !== 'production') {
66 | echo "
Debug of the current configuration object
";
67 | debug(\Flight::config()->item());
68 | } else {
69 | echo 'DISABLED';
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Flight MVC
2 |
3 | ## Description
4 | This is my take on a simple extension to implement a more 'classic' MVC pattern that runs on top of the Flight micro-framework. Flight is a great, lightweight framework for PHP. I happen to find it a little easier to work in a more traditional MVC type of structure. This extension of Flight establishes that structure and also adds in a few features like:
5 |
6 | * a PDO wrapper
7 | * a Router to read the controller, command, and 2 parameters
8 | * multiple environments and config files
9 | * a debugger function
10 | * a logger
11 | * an HTML head section builder
12 | * a input filter class (static methods)
13 |
14 | ##Installation
15 | Clone or download this repository and then run Composer's update feature to install dependencies (like Flight!). You can modify the `composer.json` files section on `require-dev` to get rid of or add development libraries like Phing, Codesniffer, phpUnit, etc.
16 |
17 | ## Unit testing
18 | All of the classes in this mod are unit tested with phpUnit, you will find the tests in the /tests directory
19 |
20 | ## Documentation
21 | Documentation for Flight is at: [http://flightphp.com]
22 |
23 | All extension documentation is in the Docs folder. You can also view the documentation using the `doc` controller (e.g. `http://example.com/doc`)
24 |
25 | ## Contributing
26 | Fork this repository and send a pull request. Please stick to issues on the issue tracker or to-do's in the individual files as my intent is to keep this repo as lightweight as possible, and I do not intend to make it a full featured extension of the Flight framework. If you have an idea for a feature, submit it to the issue tracker and let's talk it out before you start coding. I have some ideas too, but some may end up as different extensions rather than features in this extension of Flight. Remember, it is a 'micro-framework' after all.
27 |
28 | ###Conventions
29 | This extension follows PSR-1, PSR-2, and PSR-4 conventions for autoloading, structure, and style. All contributions should follow these conventions. I recommend checking with Codesniffer to be sure.
30 |
31 | ##Thanks/Credits
32 | * Mike Cao: developer of the Flight micro-framework [http://flightphp.com]
33 | * Emanuil Rusev: for the Parsedown Library that runs the doc viewer [http://erusev.com]
34 |
--------------------------------------------------------------------------------
/tests/core/RestApiCallerTest.php:
--------------------------------------------------------------------------------
1 |
10 | * @copyright 2014
11 | * @license /license.txt
12 | */
13 | use fmvc\core\helper\RestApiCaller;
14 |
15 | class RestApiCallerTest extends PHPUnit_Framework_TestCase
16 | {
17 | public $baseUrl;
18 |
19 |
20 | public function setUp()
21 | {
22 | require_once '../core/helper/RestApiCaller.php';
23 | $this->baseUrl = 'http://localhost:8888/flight-MVC/tests/api_test/' ;
24 | }
25 |
26 | public function testGet()
27 | {
28 | $url = $this->baseUrl . 'get.php';
29 | $data = RestApiCaller::get($url);
30 | $this->assertEquals('Testing Get Call', $data);
31 | }
32 |
33 | public function testPostFields()
34 | {
35 | $url = $this->baseUrl . 'post.php';
36 | $data = array('a' => 'Foo', 'b' => 'Bar');
37 | $type = 'fields';
38 |
39 | $this->assertEquals('Bar', RestApiCaller::post($url, $data, $type));
40 | }
41 |
42 | public function testPostJson()
43 | {
44 | $url = $this->baseUrl . 'post-json.php';
45 | $data = array('a' => 'Foo', 'b' => 'Bar');
46 | $type = 'json';
47 |
48 | $result = json_decode(RestApiCaller::post($url,$data,$type));
49 | $this->assertEquals('Bar', $result->b);
50 | }
51 |
52 | public function testPostXml()
53 | {
54 | $url = $this->baseUrl . 'post-xml.php';
55 | $data = 'Some text to test';
56 | $type = 'xml';
57 |
58 | $result = RestApiCaller::post($url,$data,$type);
59 | $this->assertEquals('Some text to test', $result);
60 | }
61 |
62 | public function testPutJson()
63 | {
64 | $url = $this->baseUrl . 'put.php';
65 | $data = array('a' => 'Foo', 'b' => 'Bar');
66 | $type = 'json';
67 | $result = json_decode(RestApiCaller::put($url,$data,$type));
68 |
69 | $this->assertEquals('Bar', $result->b);
70 | }
71 |
72 | public function testDelete()
73 | {
74 | $url = $this->baseUrl . 'delete.php';
75 | $result = RestApiCaller::delete($url);
76 | $this->assertEquals('Working', $result);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/core/functions/global_functions.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014
10 | * @license /license.txt
11 | */
12 |
13 | if (! function_exists('debug')) {
14 | /**
15 | * Debugger Function: echoes the provided information in an easier
16 | * to read format on screen
17 | *
18 | * @param string $input
19 | */
20 | function debug($input)
21 | {
22 | echo '
' . print_r($input, true) . '
';
23 | }
24 | }
25 |
26 | if (! function_exists('setEnvironment')) {
27 | /**
28 | * Manages the running mode of the app. There is an auto-detect feature
29 | * that sets the mode to development if it detects that the server is
30 | * 127.0.0.1, localhost, or the domain is .dev or .local
31 | *
32 | * The auto-detect will go to testing otherwise. It will never automatically
33 | * put the site into production mode.
34 | *
35 | * The auto-detect feature can be overridden by specifying the desired run mode.
36 | *
37 | * @param null $mode
38 | * @return null|string
39 | *
40 | * @TODO: set up a way to put in User defined configurations (servers, etc)
41 | * @TODO: fix the hacky double foreach....
42 | */
43 |
44 | function setEnvironment($mode = null)
45 | {
46 | $runMode = 'testing';
47 | $arrVars = array(
48 | $_SERVER['HTTP_HOST'],
49 | $_SERVER['SERVER_NAME'],
50 | $_SERVER['REMOTE_ADDR']
51 | );
52 |
53 | $arrLocal = array(
54 | '127.0.0.1',
55 | '.dev',
56 | '.local',
57 | 'localhost'
58 | );
59 |
60 | if (is_null($mode)) {
61 | echo array_search($arrLocal, $arrVars);
62 | foreach ($arrVars as $value) {
63 | foreach ($arrLocal as $srchValue) {
64 | if (stristr($value, $srchValue)) {
65 | return 'development';
66 | }
67 | }
68 | }
69 |
70 | // Set the Environment as specified if a value is passed
71 | } else {
72 | $runMode = $mode;
73 | }
74 | return $runMode;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/core/lib/Controller.php:
--------------------------------------------------------------------------------
1 |
13 | * @copyright 2014
14 | * @license /license.txt
15 | */
16 | namespace fmvc\core\lib;
17 |
18 | class Controller
19 | {
20 | /**
21 | * Configuration Dependency
22 | * @var Config
23 | */
24 | public $config;
25 |
26 | /**
27 | * Input Dependency
28 | * @var Input
29 | */
30 | public $input;
31 |
32 | /**
33 | * Name of the current class
34 | * @var string
35 | */
36 | public $class;
37 |
38 | /**
39 | * Base url of the web server
40 | * @var
41 | */
42 | public $base_server;
43 |
44 | /**
45 | * A message to pass to the UI
46 | * @var string
47 | */
48 | public $message;
49 |
50 | /**
51 | * Array of the URL Parameters
52 | * @var array
53 | */
54 | public $param = array();
55 |
56 | public function __construct(array $arrDep = array(), array $arrParam = array())
57 | {
58 | // Load Dependencies
59 | if (empty($arrDep)) {
60 | throw new \Exception('Dependency Failure');
61 | } else {
62 | foreach ($arrDep as $key => $object) {
63 | $this->$key = $object;
64 | }
65 | }
66 |
67 | // Load Parameters into Class Property
68 | if (! empty($arrParam)) {
69 | foreach ($arrParam as $value) {
70 | $this->param[] = $value;
71 | }
72 | }
73 |
74 | if (isset($this->input->server['HTTP_HOST'])) {
75 | $this->base_server = $this->input->server['HTTP_HOST'];
76 | } else {
77 | $this->base_server = $this->input->server['DOCUMENT_ROOT'];
78 | }
79 |
80 | $this->class = $this->setClassName();
81 |
82 | }
83 |
84 | /**
85 | * Get the name of the current Class
86 | * @return string Class name
87 | */
88 | protected function setClassName()
89 | {
90 | $class = get_class($this);
91 | $arr = explode('\\', $class);
92 | return end($arr);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/docs/command_line.md:
--------------------------------------------------------------------------------
1 | #Flight-MVC Command Line Interface
2 | Flight-MVC has a command line interface to make some tasks more automated in an effort to speed up development and maintenance. The following functions are available from the command line:
3 | * Start or Halt the site
4 | * Set the environment (development, testing, etc.)
5 | * Create a Model file
6 | * Create a Controller file
7 | * Create a View file
8 |
9 | ##Usage:
10 | Call the command line interface (shown here from the `cli` directory) using: `./fmvc commandName parameter1`
11 |
12 | ##Start/Stop and Environment
13 | The `environment` command can be used to start or halt the site as well as change the environment of the application.
14 |
15 | ####Valid Parameters
16 | * halt: inserts code into the `config\environment.php` file that causes the all code to stop executing
17 | * start: restarts the site by removing the halt code
18 | * auto: puts the environment into auto-detect mode
19 | * : you can pass development, testing, or any other valid environment mode you have specified.
20 |
21 | ####Examples
22 | ```
23 | //shut down the site
24 | ./fmvc environment halt
25 |
26 | //start the site from a halt
27 | ./fmvc environment start
28 |
29 | //change to development environment
30 | ./fmvc environment development
31 | ```
32 |
33 | ##Create a model, controller, or view
34 | The command line interface helps to automate the creation of common MVC file to speed up development. From the command line, you can create a new controller, model, or view file that will contain all of the code needed to get each type of object started.
35 |
36 | When creating an object, you can also specify subdirectory (and child namespace for models & controllers) to create the object in. If the subdirectory does not exist, it will be created for you. Additionally, the object generator will also check to see if the file you are trying to create already exists.
37 |
38 | ####Examples:
39 | Create a controller called `Test` in the `application/controller` directory
40 | ```
41 | ./fmvc controller test
42 | ```
43 |
44 | Create a controller called `Test` in the `application/controller/sample` directory
45 | ```
46 | ./fmvc controller sample/test
47 | ```
48 |
49 | Create a model called `Sample` in the `application/model` directory
50 | ```
51 | ./fmvc model sample
52 | ```
53 |
54 | Create a view called main.php in the `view/home` directory
55 | ```
56 | ./fmvc view home/main
57 | ```
58 |
59 |
--------------------------------------------------------------------------------
/tests/cli/CliFilegenTest.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2013
9 | * @license /license.txt
10 | */
11 | class CliFilegenTest extends PHPUnit_Framework_TestCase
12 | {
13 |
14 | public function setUp()
15 | {
16 | require_once '../cli/lib/Filegen.php';
17 | }
18 |
19 | public function tearDown()
20 | {
21 | if (file_exists('temp/test.php')) unlink('temp/test.php');
22 | if (file_exists('temp/my')) rmdir('temp/my');
23 | }
24 |
25 | public function testCreateObject()
26 | {
27 | $fgen = new \fmvc\cli\lib\Filegen();
28 | $result = $fgen->createObject('controller', 'test', 'temp/', '../cli/templates/');
29 | $text = file_get_contents('temp/Test.php');
30 | $test = (stristr($text, 'class Test extends \fmvc\core\lib\Controller') !== false) ? true : false;
31 | $this->assertFileExists('temp/Test.php');
32 | unlink('temp/Test.php');
33 | $this->assertTrue($test);
34 | }
35 |
36 | public function testCreateObjectWithSubdir()
37 | {
38 | $fgen = new \fmvc\cli\lib\Filegen();
39 | $result = $fgen->createObject('controller', 'my/test', 'temp/', '../cli/templates/');
40 | $text = file_get_contents('temp/my/Test.php');
41 | $test = (stristr($text, 'class Test extends \fmvc\core\lib\Controller') !== false) ? true : false;
42 | $this->assertFileExists('temp/my/Test.php');
43 | unlink('temp/my/Test.php');
44 | rmdir('temp/my');
45 | $this->assertTrue($test);
46 | }
47 |
48 | public function testCreateView()
49 | {
50 | $fgen = new \fmvc\cli\lib\Filegen();
51 | $result = $fgen->createObject('view', 'test', 'temp/', '../cli/templates/');
52 | $text = file_get_contents('temp/test.php');
53 | $test = (stristr($text, '') !== false) ? true : false;
54 | $this->assertFileExists('temp/test.php');
55 | unlink('temp/test.php');
56 | $this->assertTrue($test);
57 | }
58 |
59 | /**
60 | * @expectedException Exception
61 | */
62 | public function testCreateObjectFailAlreadyExists()
63 | {
64 | file_put_contents('temp/test.php', 'test 123');
65 | $fgen = new \fmvc\cli\lib\Filegen();
66 | $result = $fgen->createObject('view', 'test', 'temp/', '../cli/templates/');
67 | }
68 |
69 | /**
70 | * @expectedException Exception
71 | */
72 | public function testCreateWriteFileFailure()
73 | {
74 | mkdir('temp/my');
75 | chmod('temp/my', 0000);
76 | $fgen = new \fmvc\cli\lib\Filegen();
77 | $result = $fgen->createFile('temp/my', null, null);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/docs/html_head_generator.md:
--------------------------------------------------------------------------------
1 | #Managing the `` section of an HTML page
2 |
3 | The `` section of your HTML pages can be managed with the HTML Head helper class. This class loads automatically when the controller loads. This helper is designed primarily to manage 3 things:
4 | * Including stylesheets (CSS files)
5 | * Including Javascript files
6 | * Manipulating the `` tag of a page.
7 |
8 | Other tags can be written in to the head section of your pages using views and/or layouts, but as stylesheets, scripts, and titles are often dynamic within the application, support for easy manipulation of these is provided via the helper.
9 |
10 | The default title for the application can be set in the configuration file for each running environment using the `$config['default_title']` element of the configuration array. This will be used if the title is not set at runtime.
11 |
12 | ##Usage
13 | The class expects javascript file to be located in the `./web/scripts` directory, or a subdirectory of it. It also expects javascript files to end in the `.js` file extension. Likewise, stylesheets should be located in the `./web/css` directory (or a subdirectory) and end with the `.css` file extension.
14 |
15 | To use the helper, call the `style()` or `script()` methods and pass an array of filenames (no extension) to the method. If you were trying to load a file in subdirectory, your would prefix the filename with the directory name and a `/` character (e.g. `subdir/file`). You can pass multiple array elements to load multiple script or stylesheet files with a single method call.
16 |
17 | To change the page title, call the `title()` method and use a string for whatever title you want to use.
18 |
19 | ####Let's do an example....from a controller command:
20 | ```
21 | public function index()
22 | {
23 | //add a style sheet
24 | $this->head->style(array('main'));
25 |
26 | //add script files
27 | $this->head->script(array('foojava', 'barjava', 'foobar/java'));
28 |
29 | //change the title
30 | $this->head->title('My title');
31 |
32 | //Pass the head section as the $head variable to the view via a render call
33 | \Flight::render('home/index', array('html_head' => $this->head->head()));
34 | }
35 |
36 | ```
37 |
38 | ####In the view....
39 | ```
40 |
41 |
42 | =$html_head?>
43 |
44 |
45 |
46 | ```
47 |
48 | ####Will produce.....
49 | ```
50 |
51 |
52 |
53 |
54 |
55 |
56 | My title
57 |
58 |
59 | ```
--------------------------------------------------------------------------------
/cli/lib/Environment.php:
--------------------------------------------------------------------------------
1 |
10 | * @copyright 2014
11 | * @license /license.txt
12 | */
13 | namespace fmvc\cli\lib;
14 |
15 | class Environment
16 | {
17 | public $fileName;
18 |
19 | public $mode;
20 |
21 | public function __construct($mode = null, $filename = null)
22 | {
23 | if (is_null($mode) || is_null($filename)) {
24 | throw new \Exception("Mode and Filename are required. \r\n");
25 | } else {
26 | $this->mode = $mode;
27 | $this->fileName = $filename;
28 | }
29 | }
30 |
31 | /**
32 | * Changes the mode of the application between
33 | * start and stop depending on the mode given
34 | * @return bool
35 | */
36 | public function toggleHalt()
37 | {
38 | if ($this->mode === 'halt') {
39 | $string = "mode == 'start') {
41 | $string = "fileName);
46 | $arrFile[0] = $string;
47 | return $this->writeFile(implode($arrFile));
48 | }
49 |
50 |
51 | /**
52 | * Changes the running environment based on class properties
53 | * @return bool
54 | */
55 | public function toggleEnvironment()
56 | {
57 | switch ($this->mode)
58 | {
59 | // Turn on the auto-detector
60 | case 'auto':
61 | $string = "define('APP_ENVIRONMENT', null);\r\n";
62 | break;
63 |
64 | // if it accidentally got here from a start/stop command
65 | case 'start':
66 | case 'halt':
67 | return false;
68 | break;
69 |
70 | // all other cases, set the environment
71 | default:
72 | $string = "define('APP_ENVIRONMENT', '".$this->mode."');\r\n";
73 | break;
74 | }
75 | $arrFile = file($this->fileName);
76 | $arrFile[24] = $string;
77 | return $this->writeFile(implode($arrFile));
78 | }
79 |
80 |
81 | /**
82 | * Writes changes out to the environment file
83 | * @param $content
84 | * @return bool
85 | */
86 | public function writeFile($content)
87 | {
88 | $handle = fopen($this->fileName, "w");
89 | $result = fwrite($handle, $content);
90 | if ($result !== strlen($content) || $result === 0) {
91 | return false;
92 | } else {
93 | return true;
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/cli/fmvc:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
13 | * @copyright 2014
14 | * @license /license.txt
15 | */
16 |
17 |
18 |
19 | //assure running from command line
20 | if (php_sapi_name() !== 'cli') {
21 | die("Error 403: Access Forbidden! \r\n");
22 | }
23 |
24 | // Get any arguements passed in.
25 |
26 | $args = array();
27 | $args = $_SERVER['argv'];
28 |
29 | $command = $args[1];
30 | $param1 = $args[2];
31 |
32 |
33 | switch ($command)
34 | {
35 | /**
36 | * Command line function for starting/stopping the app
37 | * or also changing the environment (e.g. development,
38 | * testing, etc.)
39 | *
40 | */
41 | case 'environment':
42 | try {
43 | require_once 'lib/Environment.php';
44 | $env = new \fmvc\cli\lib\Environment($param1, '../config/environment.php');
45 | switch ($param1)
46 | {
47 | case 'start':
48 | case 'halt':
49 | $result = $env->toggleHalt();
50 | break;
51 |
52 | default:
53 | $result= $env->toggleEnvironment();
54 | break;
55 | }
56 | if ($result === true) {
57 | echo "\r\nSuccess: site is in $param1 mode \r\n";
58 | } else {
59 | throw new \Exception("ERROR: environment mode not updated! \r\n");
60 | }
61 | } catch (\Exception $e) {
62 | echo $e->getMessage();
63 | }
64 | break;
65 |
66 | /**
67 | * Construct a model, view, or controller class file and save it
68 | */
69 | case 'model':
70 | case 'controller':
71 | case 'view':
72 | try {
73 | require_once 'lib/Filegen.php';
74 | $mod = new \fmvc\cli\lib\Filegen();
75 | $applicationPath = "..".DIRECTORY_SEPARATOR."application".DIRECTORY_SEPARATOR.$command.DIRECTORY_SEPARATOR;
76 | $templatePath = ".".DIRECTORY_SEPARATOR."templates".DIRECTORY_SEPARATOR;
77 | $objectName = $param1;
78 | $result = $mod->createObject($command, $objectName, $applicationPath, $templatePath);
79 | if ($result === true) {
80 | echo "New $command created: $objectName\r\n";
81 | } else {
82 | throw new \Exception('CLI ERROR: File Generation or Creation Error');
83 | }
84 | } catch (\Exception $e) {
85 | echo $e->getMessage();
86 | }
87 |
88 | break;
89 |
90 | default:
91 | echo "CLI ERROR: The `$command` command was not found\r\n";
92 | break;
93 | }
94 |
--------------------------------------------------------------------------------
/docs/controllers.md:
--------------------------------------------------------------------------------
1 | #Using Controllers
2 |
3 | ##General
4 | * All controller classes must extend the `\core\lib\Controller` class
5 | * example: `class Home extends \core\lib\Controller`
6 | * Controllers should typically be located in the `application\controller\` directory and should also be in that namespace as well
7 | * The name of the controller class must be the same as its filename.
8 |
9 | ##Constructor
10 | The constructor of the controller class must call the parent constructor, as shown below
11 | ```
12 | public function __construct($deps, $params)
13 | {
14 | parent::__construct($deps, $params);
15 |
16 | }
17 | ```
18 |
19 | Other code can be added to the constructor (e.g. instantiating a data connection object into a controller class property), but the a call to the parent constructor must be part of the code.
20 |
21 | ##Dependencies
22 | When a controller is called via the URL router, it is automatically loaded with the following dependencies:
23 | * `$this->config`: The current application configuration
24 | * `$this->input` : The object containing superglobals
25 | * `this->head`: The object for managing the HTML head section of a view
26 |
27 | >Note: You can modify how/what the router automatically loads by changing the `/core/routes.php` file around line 52.
28 |
29 | ##Parameters
30 | The router also loads URL parameters into the controller each time it loads. The parameters can be found in the `$this->param` property which is an array. The first parameter is `$param[0]` and the second parameter will be loaded as `$param[1].
31 |
32 | ####Example
33 | ```
34 | http://example.com/home/index/foo/bar
35 |
36 | Controller: Home
37 | Command: index()
38 | $param[0] = 'foo'
39 | $param[1] = 'bar'
40 |
41 | ```
42 | >NOTE: at this time, only 2 parameters are supported.
43 |
44 | ##Commands
45 | Each function (and they need to have public scope) serves a a command in the controller you are working in. For example the URL: `http://example.com/home/index` will call the `index()` function in the `Home` class. Every class should typically have an `index()` command, unless you are certain that this will not be needed. If a URL is specified in a browser which has a controller but no command (e.g. `http://example.com/home`), the app will default to the `index()` command. If there is not one, a 404 error will be displayed.
46 |
47 | ##Working inside a controller command
48 | Within the command, you should be calling data from your models and then rendering it out to a view, or passing it however you want if your application is an API.
49 |
50 | ####Example
51 | ```
52 | public function viewdata()
53 | {
54 | //Open a connection to the data source
55 | $db = new \core\data\PdoConn(array('config' => \Flight::config()));
56 |
57 | //Get an array of all of the data in the companies table
58 | $rs = $db->getAll('companies');
59 |
60 | //Use Flight's rendering method to open the `views/home/viewdata.php`
61 | // view and put the data into the $data variable in the view.
62 | \Flight::render('home/viewdata', array('data' => $rs));
63 | }
64 | ```
65 |
66 |
67 |
--------------------------------------------------------------------------------
/tests/core/LoggerTest.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2013
9 | * @license /license.txt
10 | */
11 |
12 | date_default_timezone_set('America/New_York');
13 | use \fmvc\core\helper\Logger;
14 | require_once '../core/helper/Logger.php';
15 | require_once '../core/lib/Config.php';
16 |
17 | class LoggerTest extends PHPUnit_Framework_TestCase
18 | {
19 | public $log;
20 | public $conf;
21 |
22 | public function setUp()
23 | {
24 | $config['error_log_path'] = 'temp/';
25 | $this->conf = new \fmvc\core\lib\Config($config);
26 | $this->log = new Logger(array('config' => $this->conf));
27 | }
28 |
29 | public function tearDown()
30 | {
31 | //exec('mv ./temp1 ./temp');
32 | //exec('chmod 0777 ./temp');
33 | }
34 |
35 | /**
36 | * @expectedException \Exception
37 | */
38 | public function testLoggerConstructorFail()
39 | {
40 | $log = new Logger();
41 | }
42 |
43 |
44 | public function testLogger()
45 | {
46 | if ( ! is_writeable('./temp/notice.txt')) {
47 | exec("chmod 777 ./temp/notice.txt");
48 | }
49 | $this->log->notice('Test 123 Notice', 'Some Data');
50 |
51 | $file = file_get_contents('temp/notice.txt');
52 | $this->assertFileExists('temp/notice.txt');
53 | $this->assertStringStartsWith('----Logged', $file);
54 | //unlink('temp/notice.txt');
55 |
56 | }
57 |
58 | /**
59 | * @expectedException \Exception
60 | */
61 | public function testLoggerFail()
62 | {
63 | if ( ! is_writeable('./temp/notice.txt')) {
64 | exec("chmod 777 ./temp/notice.txt");
65 | }
66 | $this->log->notice(null, null);
67 |
68 | $file = file_get_contents('temp/notice.txt');
69 | $this->assertFileExists('temp/notice.txt');
70 | $this->assertStringStartsWith('----Logged', $file);
71 | //unlink('temp/notice.txt');
72 |
73 | }
74 |
75 | /**
76 | * @expectedException \Exception
77 | */
78 | public function testLoggerFailMethodName()
79 | {
80 | $this->log->notic('Test 123 Notice', 'Some Data');
81 | }
82 |
83 | /**
84 | * @expectedException \Exception
85 | */
86 | public function testLoggerFailParams()
87 | {
88 | $this->log->notice();
89 | }
90 |
91 | /**
92 | * @expectedException \Exception
93 | */
94 | public function testFileOpenFail()
95 | {
96 | $this->log->levels = array_merge($this->log->levels, array('hello/hello'));
97 | $this->log->logEvent('hello/hello','test', 'test');
98 | }
99 |
100 | /**
101 | * @expectedException \Exception
102 | */
103 | public function testFileWriteFail()
104 | {
105 |
106 | if (is_writeable('./temp/notice.txt')) {
107 | exec("chmod 444 ./temp/notice.txt");
108 | }
109 | $this->log->logEvent('notice', 'test', 'test');
110 | }
111 |
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/tests/core/HtmlHeadTest.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2013
9 | * @license /license.txt
10 | */
11 | require_once '../core/helper/HtmlHead.php';
12 | require_once '../core/lib/Config.php';
13 |
14 |
15 | class HtmlHeadTest extends PHPUnit_Framework_TestCase
16 | {
17 | public $config;
18 | public $class;
19 |
20 | public function setUp()
21 | {
22 | $config = array(
23 | 'default_title' => 'Test123'
24 | );
25 | $this->config = new \fmvc\core\lib\Config($config);
26 | $this->class = new \fmvc\core\helper\HtmlHead(array('config' => $this->config));
27 |
28 | }
29 |
30 | public function tearDown() {}
31 |
32 | public function testConstructor()
33 | {
34 | $dep = array('config' => $this->config);
35 | $class = new \fmvc\core\helper\HtmlHead($dep);
36 | $this->assertEquals('Test123', $class->c_title);
37 | }
38 |
39 | /**
40 | * @expectedException \Exception
41 | */
42 | public function testConstructorFail()
43 | {
44 | $class = new \fmvc\core\helper\HtmlHead();
45 | }
46 |
47 | public function testStyle()
48 | {
49 | $this->class->style(array('testStyle'));
50 |
51 | $result = is_numeric(strpos($this->class->c_styles[0], 'testStyle'));
52 | $this->assertTrue($result);
53 | }
54 |
55 |
56 | /**
57 | * @expectedException \Exception
58 | */
59 | public function testStyleNoParam()
60 | {
61 | $this->class->style();
62 | }
63 |
64 | /**
65 | * @expectedException \Exception
66 | */
67 | public function testStyleEmptyParam()
68 | {
69 | $this->class->style(array());
70 | }
71 |
72 | /**
73 | * @expectedException \Exception
74 | */
75 | public function testScriptNoParam()
76 | {
77 | $this->class->script();
78 | }
79 |
80 | /**
81 | * @expectedException \Exception
82 | */
83 | public function testScriptEmptyParam()
84 | {
85 | $this->class->style(array());
86 | }
87 |
88 | public function testScript()
89 | {
90 | $this->class->script(array('testScript'));
91 |
92 | $result = is_numeric(strpos($this->class->c_scripts[0], 'testScript'));
93 | $this->assertTrue($result);
94 | }
95 |
96 | public function testTitle()
97 | {
98 | $this->class->title('NewTitle');
99 | $title = $this->class->c_title;
100 | $this->assertEquals('NewTitle', $title);
101 | }
102 |
103 | /**
104 | * @expectedException \Exception
105 | */
106 | public function testTitleNull()
107 | {
108 | $this->class->title();
109 | }
110 |
111 | public function testHead()
112 | {
113 | $this->class->script(array('testScript'));
114 | $this->class->style(array('testStyle'));
115 | $head = $this->class->head();
116 | $result = strpos($head, 'testScript');
117 | $this->assertTrue(is_numeric($result));
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/core/lib/Input.php:
--------------------------------------------------------------------------------
1 |
14 | * @copyright 2014
15 | * @license /license.txt
16 | */
17 | namespace fmvc\core\lib;
18 |
19 | class Input
20 | {
21 | /**
22 | * POST superglobal array
23 | * @var array
24 | */
25 | public $post = array();
26 |
27 | /**
28 | * GET superglobal Array
29 | * @var array
30 | */
31 | public $get = array();
32 |
33 | /**
34 | * SESSION superglobal array
35 | * @var array
36 | */
37 | public $session = array();
38 |
39 | /**
40 | * SERVER superglobal array
41 | * @var array
42 | */
43 | public $server = array();
44 |
45 | /**
46 | * COOKIE superglobal array
47 | * @var array
48 | */
49 | public $cookie = array();
50 |
51 | /**
52 | * Constructor: initializes the superglobals into
53 | * class properties, loads test data if we are in
54 | * development mode
55 | *
56 | * @return Input
57 | */
58 | public function __construct()
59 | {
60 | // Initialize the class properties
61 | $this->loadSuperglobals();
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * Put superglobal arrays into class properties
68 | * @return Input
69 | */
70 | public function loadSuperglobals()
71 | {
72 | if (is_array($_POST)) {
73 | $this->post= array_merge($this->post, $_POST);
74 | }
75 |
76 | if (is_array($_SERVER)) {
77 | $this->server = array_merge($this->server, $_SERVER);
78 | }
79 |
80 | if (is_array($_GET)) {
81 | $this->get = array_merge($this->get, $_GET);
82 | }
83 |
84 | if (is_array($_COOKIE)) {
85 | $this->cookie = array_merge($this->cookie, $_COOKIE);
86 | }
87 |
88 | if (session_status() === PHP_SESSION_ACTIVE) {
89 | $this->session = array_merge($this->session, $_SESSION);
90 | } else {
91 | unset($this->session);
92 | }
93 |
94 | return $this;
95 | }
96 |
97 | /**
98 | * Wrapper for setting a session variable
99 | * @param string $key array key for the session variable
100 | * @param string $value value of the session variable
101 | * @return Input
102 | */
103 | public function session($key, $value)
104 | {
105 | $_SESSION[$key] = $value;
106 | return $this;
107 | }
108 |
109 | /**
110 | * Wrapper for setting a cookie
111 | *
112 | * @param string $key name of the cookie
113 | * @param string $value value for the cookie
114 | * @param integer $lengthSec life of the cookie (30day default)
115 | * @return mixed cooke
116 | */
117 | public function cookie($key, $value, $lengthSec = 2592000)
118 | {
119 | return setcookie($key, $value, time()+$lengthSec);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/cli/lib/Filegen.php:
--------------------------------------------------------------------------------
1 |
10 | * @copyright 2013
11 | * @license /license.txt
12 | */
13 | namespace fmvc\cli\lib;
14 |
15 | class Filegen
16 | {
17 | /**
18 | * Generates a model, controller, or view from a text file in the
19 | * /cli/templates directory.
20 | *
21 | * @param string $objectType the type of object (model, view, controller)
22 | * @param string $fileName name of the object to be created, will be exploded if it has a `/`
23 | * @param string $path the location where the object will be created
24 | * @param string $templatePath location of templates for objects
25 | * @return bool
26 | * @throws \Exception
27 | *
28 | */
29 | public function createObject($objectType, $fileName, $path, $templatePath)
30 | {
31 | //Import the contents of the proper text file
32 | $string = file_get_contents("$templatePath$objectType.txt");
33 |
34 | // if there is a slash, we need to break this into a subdirectory and file
35 | // and also deal with putting the namespace another level down
36 | if (strpos($fileName, '/') !== false) {
37 | $arrParts = explode('/', $fileName);
38 | $object = ucfirst($arrParts[1]);
39 | $namespace = '\\' . strtolower($arrParts[0]);
40 | $objectFile = ucfirst($arrParts[1]) . '.php';
41 | $path .= strtolower($arrParts[0]);
42 |
43 | // otherwise blank the namespace addon and prep the file and class names
44 | } else {
45 | $object = ucfirst($fileName);
46 | $namespace = '';
47 | $objectFile = ucfirst($fileName . '.php');
48 | }
49 |
50 | // We do not want views to have a capital letter in the file name
51 | if ($objectType == 'view') {
52 | $objectFile = strtolower($objectFile);
53 | }
54 |
55 | // replace the variable placeholders in the template with the object values
56 | $string = str_replace('{MODEL_NAME}', $object, $string);
57 | $string = str_replace('{SUBDIR_NAME}', $namespace, $string);
58 |
59 | //check to make sure it doesn't already exist before committing
60 | if (file_exists($path.$objectFile)) {
61 | throw new \Exception("CLI ERROR: $path$objectFile already exists\r\n");
62 | } else {
63 | return $this->createFile($path, $objectFile, $string);
64 | }
65 |
66 | }
67 |
68 | /**
69 | * Writes out the object file
70 | *
71 | * @param string $path path to the file
72 | * @param string $name the name of the file with extension
73 | * @param string $contents the contents of the file to be written
74 | * @return bool
75 | * @throws \Exception
76 | */
77 | public function createFile($path, $name, $contents)
78 | {
79 | if (file_exists($path . DIRECTORY_SEPARATOR) === false) {
80 | mkdir($path . DIRECTORY_SEPARATOR, 0755);
81 | }
82 |
83 | if (! is_writeable($path)) {
84 | throw new \Exception('File Could not be written');
85 | } else {
86 | file_put_contents($path . DIRECTORY_SEPARATOR .$name, $contents."\r\n");
87 | return true;
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/core/routes.php:
--------------------------------------------------------------------------------
1 |
16 | * @copyright 2014
17 | * @license /license.txt
18 | */
19 |
20 | // Remap the not found function
21 | Flight::map('notFound', function () {
22 | Flight::render('404.php');
23 | });
24 | //Use Windows Authentication to assure that there is
25 | //a legitimate user logged into the browser. App depends on Windows Auth via IIS
26 | //If we find an AUTH_USER in the IE Server Variable, set it as a configuration item
27 | //If not, render a 401 error
28 |
29 | if (Flight::config()->item('use_windows_auth') == true) {
30 | if (!isset(Flight::input()->server['AUTH_USER'])
31 | or is_null(Flight::input()->server['AUTH_USER'])
32 | or Flight::input()->server['AUTH_USER'] == '') {
33 | Flight::render('401.php');
34 | Flight::stop();
35 | } else {
36 | $t_user = strtoupper(str_replace(Flight::config()->item('auth_domain'), '', Flight::input()->server['AUTH_USER']));
37 | Flight::config()->set('auth_user', $t_user);
38 | //process any additional user authentication here (e.g. load your user class
39 |
40 | }
41 | }
42 |
43 | // Set up a route handler for Application Controllers
44 | // Route accepts a controller, command and 2 arguments
45 | Flight::route('(/@controller(/@command(/@arg1(/@arg2))))', function ($controller, $command, $arg1, $arg2) {
46 | // Set `home` as the default controller
47 | if (! isset($controller)) {
48 | $controller = 'home';
49 | }
50 |
51 | // Set `index` as the default route
52 | if (! isset($command)) {
53 | $command = 'index';
54 | }
55 |
56 | // Set the controller name and command as config variables
57 | \Flight::config()->set('controller', $controller);
58 | \Flight::config()->set('command', $command);
59 |
60 | // Build a fully qualified controller name
61 | $fqController = 'fmvc\application\controller\\' . ucfirst($controller);
62 |
63 | try {
64 | // Put parameters into array
65 | $arrParam = array($arg1, $arg2);
66 |
67 | // Designate Dependencies to Pass into Controller
68 | // ** Always make the Config and Input classes
69 | // ** available to the controller
70 | $arrDep = array(
71 | 'config' => Flight::config(),
72 | 'input' => Flight::input(),
73 | 'head' => Flight::head()
74 | );
75 |
76 | // Check for the controller, if it doesn't exist, go to 404
77 | if (! class_exists($fqController)) {
78 | Flight::render('404.php');
79 | Flight::stop();
80 | }
81 |
82 | // Load the controller & call the designated method
83 | $ctrl = new $fqController($arrDep, $arrParam);
84 |
85 | // If someone tries to call a private or protected controller method...
86 | $reflection = new \ReflectionMethod($ctrl, $command);
87 | if (! $reflection->isPublic()) {
88 | Flight::render('404.php');
89 | Flight::stop();
90 | }
91 |
92 | // Return a 404 error if the command is not valid
93 | if (! method_exists($fqController, $command)) {
94 | Flight::render('404.php');
95 | } else {
96 | $ctrl->$command();
97 | }
98 |
99 | } catch (\Exception $e) {
100 | echo $e->getMessage();
101 | }
102 | });
103 |
104 |
105 | // Catch all route for undefined routes in case the request
106 | // gets past the router above
107 | Flight::route('*', function () {
108 | Flight::render('404.php');
109 | });
110 |
--------------------------------------------------------------------------------
/core/helper/Logger.php:
--------------------------------------------------------------------------------
1 |
17 | * @copyright 2013
18 | * @license /license.txt
19 | *
20 | * @todo: Provide a configurable option to write log to SQLite database
21 | * @todo: Maybe add an API to read the logs into JSON or something like that.
22 | * @todo: Look at adapting this Logger to PSR-3
23 | *
24 | *
25 | */
26 | namespace fmvc\core\helper;
27 |
28 | class Logger
29 | {
30 | /**
31 | * Configuration Dependency
32 | * @var Config
33 | */
34 | public $config;
35 |
36 | /**
37 | * Types of logging events, add to this as desired
38 | * @var array
39 | */
40 | public $levels = array(
41 | 'event',
42 | 'notice',
43 | 'warning',
44 | 'error',
45 | );
46 |
47 | public function __construct(array $arrDep = array())
48 | {
49 | if (empty($arrDep)) {
50 | throw new \Exception('Dependency Failure');
51 | } else {
52 | foreach ($arrDep as $key => $object) {
53 | $this->$key = $object;
54 | }
55 | }
56 | }
57 |
58 | /**
59 | * Dynamic method caller that will allow you to use the log level as
60 | * the method name
61 | *
62 | * e.g. $log->notice($message, $data)
63 | *
64 | * @param string $method name of the method which will map to the event level
65 | * @param array $arrParams
66 | */
67 | public function __call($method, $arrParams)
68 | {
69 | $this->logEvent($method, $arrParams[0], $arrParams[1]);
70 | }
71 |
72 | /**
73 | * Logs an event and writes it to the appropriate log file
74 | *
75 | * @param null|string $level log level
76 | * @param null|string $message human readable message
77 | * @param null|mixed $data additional data
78 | * @return int|bool number of bytes on success, false on failure
79 | * @throws \Exception
80 | */
81 | public function logEvent($level = null, $message = null, $data = null)
82 | {
83 | // First 2 parameters are required, so fail if one is missing
84 | if (is_null($level) || is_null($message)) {
85 | throw new \Exception('Level and Log Message are Both Required');
86 | } else {
87 |
88 | // Make sure this is a valid message level
89 | $this->checkLevelIsValid($level);
90 |
91 | // Compose the Log Message
92 | $logMessage = "----Logged $level: ".date('m-d-Y h:m:sa', time())."----- \n";
93 | $logMessage .= "Message Content : [$message]\n";
94 | $logMessage .= "Additional Data : " . $data . "\n";
95 |
96 | // Open or Create the Log File, named whatever the event level is
97 | $file = $this->config->item('error_log_path').$level.'.txt';
98 | $fh = @fopen($file, 'a');
99 | if (! file_exists($file) || ! $fh || ! is_writable($file)) {
100 | // Throw an exception if we cannot get a file handle
101 | throw new \Exception('Log file cannot be opened or created');
102 | }
103 |
104 | return fwrite($fh, $logMessage);
105 | }
106 | }
107 |
108 | /**
109 | * Check to see if the log level is valid
110 | *
111 | * @param null|string $level
112 | * @throws \Exception
113 | */
114 | public function checkLevelIsValid($level = null)
115 | {
116 | if (! in_array($level, $this->levels) || is_null($level)) {
117 | throw new \Exception('Log Level is invalid');
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/core/helper/HtmlHead.php:
--------------------------------------------------------------------------------
1 | section
5 | * of an HTML file. This allows specifying of CSS and JS files
6 | * from a controller command.
7 | *
8 | * This class is automatically initialized in the bootstrap and is
9 | * preloaded & available in the controller at all times.
10 | *
11 | * Requires the config object as a dependency
12 | *
13 | * @category helper
14 | * @package core
15 | * @author Andrew Podner
16 | * @copyright 2013
17 | * @license /license.txt
18 | *
19 | * @todo: add support for other HTML head elements
20 | * @todo: add an auto-detector to allow a string or an array to be passed to style() and script() methods
21 | */
22 | namespace fmvc\core\helper;
23 |
24 | class HtmlHead
25 | {
26 | /**
27 | * Configuration Dependency
28 | * @var Config
29 | */
30 | public $config;
31 |
32 | /**
33 | * Array of script tags
34 | * @var array
35 | */
36 | public $c_scripts = array();
37 |
38 | /**
39 | * Array of style tags
40 | * @var array
41 | */
42 | public $c_styles = array();
43 |
44 | /**
45 | * Page Title
46 | * @var
47 | */
48 | public $c_title;
49 |
50 | public function __construct(array $arrDep = array())
51 | {
52 | // Load Dependencies
53 | if (empty($arrDep)) {
54 | throw new \Exception('Dependency Failure');
55 | } else {
56 | foreach ($arrDep as $key => $object) {
57 | $this->$key = $object;
58 | }
59 | }
60 |
61 | // Set the default page title
62 | $this->c_title = $this->config->item('default_title');
63 | }
64 |
65 | /**
66 | * Adds a Javascript File to the Array for the HTML HEAD
67 | * @param array $arrFile
68 | * @return Controller
69 | * @throws \Exception
70 | */
71 | public function script(array $arrFile = array())
72 | {
73 | if (empty($arrFile)) {
74 | throw new \Exception('No JavaScript Files Provided');
75 | }
76 | foreach ($arrFile as $file) {
77 | $script = '';
78 | $this->c_scripts[] = $script;
79 | }
80 | return $this;
81 | }
82 |
83 | /**
84 | * Adds a CSS File to the Array for the HTML HEAD
85 | * @param array $arrFile
86 | * @return Controller
87 | * @throws \Exception
88 | */
89 | public function style(array $arrFile = array())
90 | {
91 | if (empty($arrFile)) {
92 | throw new \Exception('No CSS Files Provided');
93 | }
94 | foreach ($arrFile as $file) {
95 | $style = '';
96 | $this->c_styles[] = $style;
97 | }
98 | return $this;
99 | }
100 |
101 | /**
102 | * Changes the Page Title from the default
103 | * @param string $title
104 | * @return Controller
105 | * @throws \Exception
106 | */
107 | public function title($title = null)
108 | {
109 | if (is_null($title)) {
110 | throw new \Exception('No Title Provided');
111 | }
112 | $this->c_title = $title;
113 | return $this;
114 | }
115 |
116 | /**
117 | * Returns the HTML HEAD Contents
118 | * @return string
119 | */
120 | public function head()
121 | {
122 | $head = '';
123 | if (! empty($this->c_scripts)) {
124 | foreach ($this->c_scripts as $link) {
125 | $head .= $link . '
126 | ';
127 | }
128 | }
129 | if (! empty($this->c_styles)) {
130 | foreach ($this->c_styles as $link) {
131 | $head .= $link . '
132 | ';
133 | }
134 | }
135 | $head .= ''.$this->c_title.'
136 | ';
137 | return $head;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/core/helper/Filter.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2013
9 | * @license /license.txt
10 | */
11 |
12 |
13 | class CliEnvironmentTest extends PHPUnit_Framework_TestCase
14 | {
15 | public $config;
16 |
17 | public function setUp()
18 | {
19 | require_once '../cli/lib/Environment.php';
20 | }
21 |
22 | public function tearDown() {}
23 |
24 | /**
25 | * @expectedException Exception
26 | */
27 | public function testNullConstructor() {
28 | $test = new \fmvc\cli\lib\Environment();
29 | }
30 |
31 | /**
32 | * @expectedException Exception
33 | */
34 | public function testNullConstructor2() {
35 | $test = new \fmvc\cli\lib\Environment('test');
36 | }
37 |
38 | public function testConstructor()
39 | {
40 | $test = new \fmvc\cli\lib\Environment('test', 'file.php');
41 | $this->assertEquals('test', $test->mode);
42 | $this->assertEquals('file.php', $test->fileName);
43 | }
44 |
45 | public function testWriteFile()
46 | {
47 | $file = 'temp/testwrite.txt';
48 | if (file_exists($file)) {
49 | unlink($file);
50 | }
51 | $env = new \fmvc\cli\lib\Environment('test', $file);
52 |
53 | file_put_contents($file, 'Test data');
54 | $this->assertTrue($env->writeFile('my test data'));
55 |
56 | $newData = file_get_contents($file);
57 | $this->assertEquals('my test data', $newData);
58 | unlink($file);
59 | }
60 |
61 | public function testWriteFileFail()
62 | {
63 | $file = 'temp/testwrite.txt';
64 | if (file_exists($file)) {
65 | unlink($file);
66 | }
67 | file_put_contents($file, 'Test data');
68 | $env = new \fmvc\cli\lib\Environment('test', $file);
69 | $this->assertFalse($env->writeFile(''));
70 | }
71 |
72 | public function testHalt()
73 | {
74 | $file = 'temp/testwrite.txt';
75 | if (file_exists($file)) {
76 | unlink($file);
77 | }
78 | file_put_contents($file, 'Test data');
79 | $env = new \fmvc\cli\lib\Environment('halt', $file);
80 | $this->assertTrue($env->toggleHalt());
81 |
82 | $data = file_get_contents($file);
83 | $this->assertStringStartsWith("assertFalse($env->toggleHalt());
95 | }
96 | public function testStart()
97 | {
98 | $file = 'temp/testwrite.txt';
99 | if (file_exists($file)) {
100 | unlink($file);
101 | }
102 | file_put_contents($file, 'Test data');
103 | $env = new \fmvc\cli\lib\Environment('start', $file);
104 | $this->assertTrue($env->toggleHalt());
105 |
106 | $data = file_get_contents($file);
107 | $this->assertEquals("assertTrue($env->toggleEnvironment());
120 |
121 | $data = file_get_contents($file);
122 | $this->assertEquals("define('APP_ENVIRONMENT', 'development');\r\n", $data);
123 | unlink($file);
124 | }
125 |
126 | public function testToggleEnvironmentFail()
127 | {
128 | $file = 'temp/testwrite.txt';
129 | if (file_exists($file)) {
130 | unlink($file);
131 | }
132 | $env = new \fmvc\cli\lib\Environment('start', $file);
133 | $this->assertFalse($env->toggleEnvironment());
134 | }
135 |
136 | public function testAutoDetect()
137 | {
138 | $file = 'temp/testwrite.txt';
139 | if (file_exists($file)) {
140 | unlink($file);
141 | }
142 | file_put_contents($file, '');
143 | $env = new \fmvc\cli\lib\Environment('auto', $file);
144 | $this->assertTrue($env->toggleEnvironment());
145 |
146 | $data = file_get_contents($file);
147 | $this->assertEquals("define('APP_ENVIRONMENT', null);\r\n", $data);
148 | unlink($file);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/docs/databases.md:
--------------------------------------------------------------------------------
1 | #Working with Databases
2 |
3 | Native support for database connections is managed through a wrapper class for the PDO class. Presently, connections to the following databases are supported in the wrapper. All methods in the wrapper class use prepared statements.
4 | * Mysql
5 | * SQL Server
6 | * ODBC
7 | * Sqlite
8 | * Postgres
9 |
10 | ##Connecting
11 | Connecting to a database is managed via the configuration file. The database configuration resides in a multi-dimensional array where each top level element is the configuration for a data connection (e.g. `$confg['db_default'])
12 |
13 | `db_default` is the fallback connection that will be used if no connection is specified when the `PdoConn` class is instantiated. If a configuration is specified, only the part after the `db_` is passed into the instantiation statement. For instance, if there is a configuration called `$config['db_foo']`, it is called with the following statement:
14 |
15 | ```
16 |
17 | $foo = new \core\data\PdoConn(array('config' => \Flight::config()), 'foo');
18 |
19 | ```
20 | The PDO connection can be directly accessed from the PdoConn object using the `conn` property (e.g. `$foo->conn`)
21 |
22 | The array elements for each type of database vary from platform to platform. The `config/config_template.php` file gives more details as to which elements are needed for each database system.
23 | * Mysql
24 | * driver: 'mysql'
25 | * host
26 | * db_user
27 | * db_password
28 | * db_name
29 | * SQL Server
30 | * driver: 'sqlsrv'
31 | * dsn
32 | * db_user
33 | * db_password
34 | * ODBC
35 | * driver: 'odbc'
36 | * dsn
37 | * db_user
38 | * db_password
39 | * Sqlite
40 | * driver: 'sqlite'
41 | * db_path (if null, `/data/sqlite` is the default path)
42 | * db_filename
43 | * Postgres
44 | * driver: 'pgsql'
45 | * host
46 | * db_user
47 | * db_password
48 | * db_name
49 |
50 | ##Dynamic Methods
51 |
52 | The PdoConn class supports a variety of dynamic method names using the PHP `__call()` magic method. There are 6 database operations supported via dynamic methods. Method names are always in camelCase with the first letter being lowercase (e.g. `getTableByField`). The system converts camelCase to underscores in the database, so your database fields and tables should always be in underscore.
53 |
54 | ####Example
55 | The dynamic method `getCompanyByCompanyName('Example')` would look for an exact match to 'Example' in the `company_name` field of the `company` table.
56 |
57 | >NOTE: you can specify a table prefix in the database configuration, `$config['db_prefix']` such as `ABC_`. If you add a prefix, then the dynamic call to `getCompanyByCompanyName('Example')` would look for the `ABC_company` table.
58 |
59 | * get: This is the basic select method. It accepts 1 parameter, which is the value of the field you are searching. The get method looks for exact matches to whatever parameter is specified. Usage: `$foo->getCompanyByAccountStatus('active')` looks for companies with an account status of active. Results are given in a multidimensional array as follows: `$row[0]['field_name']`
60 |
61 | * filter: This is a select method that accepts and sorts. It accepts 1 parameter, which is the value of the field you are searching. The get method looks for exact matches to whatever parameter is specified. Usage: `$foo->filterCompanyByAccountStatus('act*')` looks for companies with an account status that begins with `act`. Asteriks are used as wildcards. Results are given in a multidimensional array as follows: `$row[0]['field_name']`
62 |
63 | * all: This will retrieve all fields of all rows for the specified table. Usage: `$foo->allCompany()` is the same as saying "SELECT * FROM company";
64 |
65 | * insert: This mimics the SQL insert method. The parameter is a multidimensional array in the form of `$row[0]['field_name'] = 'value'` Each record to be inserted must have the same number of fields. Any number of fields in the table can be part of the insert statement. It returns the last insert id (return value may not work properly in ODBC).
66 |
67 | * update: This mimics the SQL update method. The parameters are 2 arrays, the first array is a the field names and values in the form `$row['field_name']='value'` and the second is an array for the where clause in the form of `$where['field_name']='value'`. Returns the number of affected rows.
68 |
69 | * delete: Works similar to get. Usage: `$foo->deleteCompanyByStatus('inactive')` will delete all companies with the status 'inactive'. Returns the number of affected rows.
70 |
71 | ##Other methods
72 | The get, filter, update, insert, delete, and getAll methods can also be used without calling a dynamic method name. These methods are all documented in the PDOConn class method comments.
73 |
74 | For more complex queries, it is recommended that the PDO connection be called directly using the `conn` propery (e.g. $foo->conn->prepare()). Dynamic methods are provided to reduce the lines of code needed to execute simple CRUD operations.
--------------------------------------------------------------------------------
/core/helper/RestApiCaller.php:
--------------------------------------------------------------------------------
1 |
10 | * @copyright 2014
11 | * @license /license.txt
12 | */
13 | namespace fmvc\core\helper;
14 |
15 | class RestApiCaller
16 | {
17 |
18 | /**
19 | * Simple function to manage a get request.
20 | *
21 | * @param string $url location to make the API call to
22 | * @return string the data returned by the API call
23 | */
24 | public static function get($url)
25 | {
26 | return file_get_contents($url);
27 | }
28 |
29 | /**
30 | * Helper function that manages post requests via cURL. It
31 | * will accept an associative array or an XML string.
32 | *
33 | * @param string $url Location to make the API call to
34 | * @param mixed $data associative array or XML string
35 | * @param string $dataType `fields`, `json`, or `xml`
36 | * @return boolean true return value of curl_exec() call
37 | *
38 | */
39 | public static function post($url, $data, $dataType)
40 | {
41 | $curlInput = self::prepareData($data, $dataType);
42 |
43 | $ch = curl_init();
44 | curl_setopt_array(
45 | $ch,
46 | array(
47 | CURLOPT_URL => $url,
48 | CURLOPT_HEADER => false,
49 | CURLOPT_RETURNTRANSFER => true,
50 | CURLOPT_POST => 1,
51 | CURLOPT_HTTPHEADER => array(
52 | 'Content-Type: ' . $curlInput['type'],
53 | 'Content-Length: ' . strlen($curlInput['data'])
54 | ),
55 | CURLOPT_POSTFIELDS => $curlInput['data'],
56 | )
57 | );
58 | $result = curl_exec($ch);
59 | curl_close($ch);
60 | return $result;
61 | }
62 |
63 | /**
64 | * send delete request to API
65 | * @param $url
66 | * @return mixed
67 | */
68 | public static function delete($url)
69 | {
70 | $ch = curl_init();
71 | curl_setopt_array(
72 | $ch,
73 | array(
74 | CURLOPT_URL => $url,
75 | CURLOPT_HEADER => false,
76 | CURLOPT_RETURNTRANSFER => true,
77 | CURLOPT_CUSTOMREQUEST => "DELETE",
78 | )
79 | );
80 | $result = curl_exec($ch);
81 | curl_close($ch);
82 | return $result;
83 | }
84 |
85 | /**
86 | * Helper function that manages post requests via cURL. It
87 | * will accept an associative array or an XML string.
88 | *
89 | * @param string $url Location to make the API call to
90 | * @param mixed $data associative array or XML string
91 | * @param string $dataType `fields`, `json`, or `xml`
92 | * @return boolean true return value of curl_exec() call
93 | *
94 | */
95 | public static function put($url, $data, $dataType)
96 | {
97 | $curlInput = self::prepareData($data, $dataType);
98 |
99 | $ch = curl_init();
100 | curl_setopt_array(
101 | $ch,
102 | array(
103 | CURLOPT_URL => $url,
104 | CURLOPT_RETURNTRANSFER => true,
105 | CURLOPT_CUSTOMREQUEST => "PUT",
106 | CURLOPT_HTTPHEADER => array(
107 | 'Content-Type: ' . $curlInput['type'],
108 | 'Content-Length: ' . strlen($curlInput['data'])
109 | ),
110 | CURLOPT_POSTFIELDS => $curlInput['data'],
111 | )
112 | );
113 | $result = curl_exec($ch);
114 | curl_close($ch);
115 | return $result;
116 | }
117 |
118 | /**
119 | * Prepares the data string to go into a PUT or POST
120 | * request
121 | *
122 | * @param mixed $data either an XML string or associative array
123 | * @param string $dataType type of data (`xml`, `json`, `fields`)
124 | * @return array associative array where `data` is the formatted data string and `type`
125 | * is the Content Type string for the HTTP request
126 | *
127 | */
128 | protected static function prepareData($data, $dataType)
129 | {
130 | switch ($dataType)
131 | {
132 | // accepts an associative array of data (like $_POST from a form)
133 | case 'fields':
134 | $curlData = http_build_query($data);
135 | $contentType = 'application/x-www-form-urlencoded';
136 | break;
137 |
138 | // expects an associative array and converts to JSON
139 | case 'json':
140 | $curlData = json_encode($data);
141 | $contentType = 'application/json';
142 | break;
143 |
144 | //expects a properly formatted XML string
145 | case 'xml':
146 | $curlData = $data;
147 | $contentType = 'text/xml';
148 | break;
149 | }
150 | return array('data' => $curlData, 'type' => $contentType);
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/tests/core/FilterTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(Filter::filename($val));
29 | }
30 |
31 | $bad = array(
32 | 'config-test.php',
33 | 'co(fig.php',
34 | 'me@example.com'
35 | );
36 |
37 | foreach($bad as $badVal)
38 | {
39 | $this->assertFalse(Filter::filename($badVal));
40 | }
41 |
42 |
43 | }
44 |
45 | public function testInteger()
46 | {
47 | $vals = array(1,2354,6543,2,24);
48 | $badVals = array('x','ABCD', 1.5, '1.33');
49 |
50 | foreach ($vals as $val)
51 | {
52 | $this->assertTrue(Filter::integer($val),"Tested $val for Integer Filter");
53 | }
54 |
55 | foreach ($badVals as $bad) {
56 | $this->assertFalse(Filter::integer($bad), "Tested $bad for Numeric Fail Filter");
57 | }
58 | }
59 |
60 | public function testNumeric()
61 | {
62 | $vals = array(1,2354,6543,2,24.6,1.2354);
63 | $badVals = array('x','ABCD','1.33z');
64 |
65 | foreach ($vals as $val)
66 | {
67 | $this->assertTrue(Filter::numeric($val), "Tested $val for Numeric Filter");
68 | }
69 |
70 | foreach ($badVals as $bad) {
71 | $this->assertFalse(Filter::numeric($bad), "Tested $bad for Numeric Fail Filter");
72 | }
73 | }
74 |
75 | public function testAlphanumeric()
76 | {
77 | $vals = array(2354,6543,'2abcs', 'mnlkkjdsa', 'asdejfjaASDEV1234');
78 | $badVals = array('space Val','ABCD@','1.33z', 'test-value', 'test_value');
79 |
80 | foreach ($vals as $val)
81 | {
82 | $this->assertTrue(Filter::alphanumeric($val), "Tested $val for Alphanumeric Filter");
83 | }
84 |
85 | foreach ($badVals as $bad) {
86 | $this->assertFalse(Filter::alphanumeric($bad), "Tested $bad for Numeric Fail Filter");
87 | }
88 | }
89 |
90 | public function testAlpha()
91 | {
92 | $vals = array('abcs', 'mnlkkjdsa', 'asdejfjaASDEV');
93 | $badVals = array('space Val','ABCD@','1.33z', 'test-value', 'test_value');
94 |
95 | foreach ($vals as $val)
96 | {
97 | $this->assertTrue(Filter::alpha($val), "Tested $val for Alpha Filter");
98 | }
99 |
100 | foreach ($badVals as $bad) {
101 | $this->assertFalse(Filter::alpha($bad), "Tested $bad for Alpha Fail Filter");
102 | }
103 | }
104 |
105 |
106 | public function testEmail()
107 | {
108 | $vals = array('test@mail.test.com', 'p.diddy@example.net', 'joe_blow@test.org');
109 | $badVals = array('www.test.com','joe@example','tim#excampl.com');
110 |
111 | foreach ($vals as $val)
112 | {
113 | $this->assertTrue(Filter::email($val), "Tested $val for Email Filter");
114 | }
115 |
116 | foreach ($badVals as $bad) {
117 | $this->assertFalse(Filter::email($bad), "Tested $bad for Email Fail Filter");
118 | }
119 | }
120 |
121 | public function testBoolean()
122 | {
123 | $vals = array(true, 1, 'on', 'yes');
124 | $badVals = array('www.test.com', 0, null, false);
125 |
126 | foreach ($vals as $val)
127 | {
128 | $this->assertTrue(Filter::boolean($val), "Tested $val for Boolean Filter");
129 | }
130 |
131 | foreach ($badVals as $bad) {
132 | $this->assertFalse(Filter::boolean($bad), "Tested $bad for Boolean Fail Filter");
133 | }
134 | }
135 |
136 |
137 | public function testPageName()
138 | {
139 | $vals = array('test', 'testPage1', 'test_page');
140 | $badVals = array('test-page', 'test.page', 'test page');
141 |
142 | foreach ($vals as $val)
143 | {
144 | $this->assertTrue(Filter::pageName($val), "Tested $val for PageName Filter");
145 | }
146 |
147 | foreach ($badVals as $bad) {
148 | $this->assertFalse(Filter::pageName($bad), "Tested $bad for PageName Fail Filter");
149 | }
150 | }
151 |
152 | public function testDatabaseField()
153 | {
154 | $vals = array('test', 'testPage1', 'test_page', 'test.page');
155 | $badVals = array('test-page', 'test page', 'test%page');
156 |
157 | foreach ($vals as $val)
158 | {
159 | $this->assertTrue(Filter::databaseField($val), "Tested $val for Field Filter");
160 | }
161 |
162 | foreach ($badVals as $bad) {
163 | $this->assertFalse(Filter::databaseField($bad), "Tested $bad for Field Fail Filter");
164 | }
165 | }
166 |
167 | public function testCheckDateIsValid()
168 | {
169 | $vals = array('1/12/15', '1/1/15', '01/02/2015', '12/25/2015', '12/16/14');
170 | $badVals = array('1/32/2013', '13/1/1999', '2/29/1999', '11/10/234015', '1/15');
171 |
172 | foreach ($vals as $val)
173 | {
174 | $this->assertTrue(Filter::checkDateIsValid($val), "Tested $val for Date Filter");
175 | }
176 |
177 | foreach ($badVals as $bad) {
178 | $this->assertFalse(Filter::checkDateIsValid($bad), "Tested $bad for Date Fail Filter");
179 | }
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/tests/core/PdoConnTest.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright 2013
9 | * @license /license.txt
10 | */
11 | use \fmvc\core\data\PdoConn;
12 | use \fmvc\core\lib\Config;
13 | require_once '../core/data/PdoConn.php';
14 | require_once '../core/lib/Config.php';
15 |
16 | class PdoConnTest extends PHPUnit_Framework_TestCase
17 | {
18 | public $db;
19 | public $conf;
20 | public $insert_id;
21 |
22 | public function setUp()
23 | {
24 | $config['db_default']['db_path'] = '../data/sqlite';
25 | $config['db_default']['db_filename'] = 'unit_test.db';
26 | $config['db_default']['driver'] = 'sqlite';
27 | $config['db_default']['db_prefix'] = '';
28 | $this->conf = new Config($config);
29 |
30 | $this->db = new PdoConn(array('config' => $this->conf));
31 | }
32 |
33 | public function tearDown()
34 | {
35 | $this->db = null;
36 | }
37 |
38 |
39 | public function testMysqlConnection()
40 | {
41 | $this->assertObjectHasAttribute('conn', $this->db);
42 | }
43 |
44 | /**
45 | * @expectedException \Exception
46 | */
47 | public function testSqlServerConnectionAndConnFailure()
48 | {
49 | $config2['db_default']['dsn'] = 'localhost:1433';
50 | $config2['db_default']['db_user'] = 'user';
51 | $config2['db_default']['db_password'] = 'sample';
52 | $config2['db_default']['driver'] = 'sqlsrv';
53 | $config2['db_prefix'] = '';
54 | $conf2 = new Config($config2);
55 | $db3 = new PdoConn(array('config'=>$conf2));
56 | $db3 = null;
57 | }
58 |
59 | /**
60 | * @expectedException \Exception
61 | */
62 | public function testOdbcConnectionAndConnFailure()
63 | {
64 | $config2['db_default']['dsn'] = 'localhost:9999';
65 | $config2['db_default']['db_user'] = 'user';
66 | $config2['db_default']['db_password'] = 'sample';
67 | $config2['db_default']['driver'] = 'odbc';
68 | $config2['db_prefix'] = '';
69 | $conf2 = new Config($config2);
70 | $db3 = new PdoConn(array('config'=>$conf2));
71 | $db3 = null;
72 | }
73 |
74 | /**
75 | * @expectedException \Exception
76 | */
77 | public function testMysqlConnectionAndConnFailure()
78 | {
79 | $config2['db_default']['host'] = 'localhost';
80 | $config2['db_default']['port'] = '8889';
81 | $config2['db_default']['db_user'] = 'root';
82 | $config2['db_default']['db_name'] = 'test';
83 | $config2['db_default']['db_password'] = 'mysql2';
84 | $config2['db_default']['driver'] = 'mysql';
85 | $config2['db_prefix'] = 'pims_';
86 | $conf2 = new Config($config2);
87 | $db3 = new PdoConn(array('config'=>$conf2));
88 | $db3 = null;
89 | }
90 |
91 | /**
92 | * @expectedException \Exception
93 | */
94 | public function testPostgresConnectionAndConnFailure()
95 | {
96 | $config2['db_default']['db_user'] = 'root';
97 | $config2['db_default']['db_name'] = 'test';
98 | $config2['db_default']['db_password'] = 'mysql2';
99 | $config2['db_default']['port'] ='1234';
100 | $config2['db_default']['host'] = 'localhost';
101 | $config2['db_default']['driver'] = 'pgsql';
102 | $conf2 = new Config($config2);
103 | $db3 = new PdoConn(array('config'=>$conf2));
104 | $db3 = null;
105 | }
106 |
107 | /**
108 | * @runInSeparateProcess
109 | * @expectedException \Exception
110 | */
111 | public function testPostgresPortConnectionAndConnFailure()
112 | {
113 | $config2['db_default']['db_user'] = 'root';
114 | $config2['db_default']['db_name'] = 'test';
115 | $config2['db_default']['port'] = '5444';
116 | $config2['db_default']['db_password'] = 'mysql2';
117 | $config2['db_default']['driver'] = 'pgsql';
118 | $conf2 = new Config($config2);
119 | $db3 = new PdoConn(array('config'=>$conf2));
120 | $db3 = null;
121 | }
122 |
123 |
124 | /**
125 | * @expectedException \Exception
126 | */
127 | public function testSqliteConnectionAndConnFailure()
128 | {
129 | $config2['db_default']['db_path'] = null;
130 | $config2['db_default']['driver'] = 'sqlite';
131 | $conf2 = new Config($config2);
132 | $db3 = new PdoConn(array('config'=>$conf2));
133 | $db3 = null;
134 | }
135 |
136 | /**
137 | * @expectedException \Exception
138 | */
139 | public function testConnectionDependencyFailure()
140 | {
141 | $db = new PdoConn(array());
142 | }
143 |
144 | /**
145 | *
146 | */
147 | public function testConnectionWithName()
148 | {
149 | $db2 = new PdoConn(array('config' => $this->conf), 'default');
150 | $this->assertObjectHasAttribute('conn', $db2);
151 | $db2 = null;
152 | }
153 |
154 |
155 | /**
156 | *
157 | */
158 | public function testInit()
159 | {
160 | $db2 = new PdoConn(array('config' => $this->conf), 'default');
161 | $db2->init();
162 | $this->assertObjectHasAttribute('conn', $db2);
163 | $db2 = null;
164 | }
165 |
166 | public function testOverloadGet()
167 | {
168 | $arrOutput = $this->db->getCompaniesById(1);
169 | $this->assertArrayHasKey('abbr', $arrOutput[0]);
170 | }
171 |
172 |
173 | /**
174 | * @expectedException \PDOException
175 | */
176 | public function testOverloadGetFail()
177 | {
178 | $arrOutput = $this->db->getCompaniesByIx(1);
179 | //$this->assertArrayHasKey('abbr', $arrOutput[0]);
180 | }
181 |
182 | public function testOverloadFiler()
183 | {
184 | $arrOutput = $this->db->filterCompaniesById(1);
185 | $this->assertArrayHasKey('abbr', $arrOutput[0]);
186 | }
187 | public function testFilterSort()
188 | {
189 | $arrOutput = $this->db->filter('companies', 'id', '1', 'abbr');
190 | $this->assertArrayHasKey('abbr', $arrOutput[0]);
191 | }
192 |
193 |
194 | public function testFilter()
195 | {
196 | $arrOutput = $this->db->filter('companies', 'id', 1);
197 | $this->assertArrayHasKey('abbr', $arrOutput[0]);
198 |
199 | $arrOutput = $this->db->filter('companies', 'id', '1*');
200 | $this->assertArrayHasKey('abbr', $arrOutput[0]);
201 |
202 |
203 | }
204 |
205 | /**
206 | * @expectedException \PDOException
207 | */
208 | public function testFilterFail()
209 | {
210 | $arrOutput = $this->db->filter('companies', 'ix', 1);
211 | //$this->assertArrayHasKey('abbr', $arrOutput[0]);
212 | }
213 |
214 | public function testOverloadInsert()
215 | {
216 | $arr = array(
217 | 'abbr' => "TST",
218 | 'descr' => "TEST COMPANY",
219 | );
220 | $result = $this->db->insertCompanies($arr);
221 | $this->insert_id = $result;
222 | $rs = $this->db->getCompaniesById($result);
223 | $this->assertArrayHasKey('abbr', $rs[0]);
224 | $this->assertEquals('TST', $rs[0]['abbr']);
225 | }
226 |
227 | /**
228 | * @expectedException \PDOException
229 | */
230 | public function testOverloadInsertFail()
231 | {
232 | $arr = array(
233 | 'abbrev' => "TST",
234 | 'descr' => "TEST COMPANY",
235 | );
236 | $result = $this->db->insertCompanies($arr);
237 |
238 | }
239 |
240 | public function testOverloadUpdate()
241 | {
242 |
243 | $arr = array('abbr' => 'TTS');
244 | $this->db->updateCompaniesByAbbr('TST' , $arr);
245 | $rs = $this->db->getCompaniesByAbbr('TTS');
246 | $this->assertArrayHasKey('abbr', $rs[0]);
247 | $this->assertEquals('TTS', $rs[0]['abbr']);
248 | }
249 |
250 | /**
251 | * @expectedException \PDOException
252 | */
253 | public function testOverloadUpdateFail()
254 | {
255 | $arr = array('abbrev' => 'TTS');
256 | $this->db->updateCompaniesById('TST', $arr);
257 | }
258 |
259 | public function testOverloadDelete()
260 | {
261 |
262 | $rs = $this->db->deleteCompaniesByAbbr('TTS');
263 | $this->assertEquals(1, $rs);
264 | }
265 |
266 | /**
267 | * @expectedException \PDOException
268 | */
269 | public function testOverloadDeleteFail()
270 | {
271 | $rs = $this->db->deleteCompaniesByIx('TTS');
272 | }
273 |
274 | public function testOverloadGetAll()
275 | {
276 | $rs = $this->db->allCompanies();
277 | $this->assertArrayHasKey('abbr', $rs[0]);
278 | }
279 |
280 | /**
281 | * @expectedException \PDOException
282 | */
283 | public function testOverloadGetAllFail()
284 | {
285 | $rs = $this->db->allCompaniess();
286 | }
287 |
288 |
289 | public function testCamelCaseToUnderscore()
290 | {
291 | $val = 'SomeTest';
292 | $expected = 'some_test';
293 | $ret = $this->db->camelCaseToUnderscore($val);
294 | $this->assertEquals($expected, $ret);
295 | }
296 |
297 | public function testGetIn()
298 | {
299 | $rs = $this->db->getIn('companies', 'id', '1');
300 | $this->assertArrayHasKey('abbr', $rs[0]);
301 | }
302 |
303 | /**
304 | * @expectedException \PDOException
305 | */
306 | public function testGetInFail()
307 | {
308 | $rs = $this->db->getIn('company', 'id', '100');
309 | $this->assertArrayHasKey('abbr', $rs[0]);
310 | }
311 |
312 | public function testDoSql()
313 | {
314 | $rs = $this->db->doSql("SELECT * FROM companies WHERE id = 1");
315 | $this->assertArrayHasKey('abbr', $rs[0]);
316 | }
317 |
318 | /**
319 | * @expectedException \PDOException
320 | */
321 | public function testDoSqlFail()
322 | {
323 | $rs = $this->db->doSql('SELECT * FROM company where id = 1');
324 | $this->assertArrayHasKey('abbr', $rs[0]);
325 | }
326 | }
327 |
--------------------------------------------------------------------------------
/core/data/PdoConn.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014
10 | * @license /license.txt
11 | *
12 | */
13 | namespace fmvc\core\data;
14 |
15 | class PdoConn
16 | {
17 | /**
18 | * PDO Connection Object
19 | * @var \PDO object
20 | */
21 | public $conn;
22 |
23 | /**
24 | * Configuration parameters (Dependency)
25 | * @var Config object
26 | */
27 | public $config;
28 |
29 | /**
30 | * Configuration for the specific database
31 | * @var
32 | */
33 | public $dbConfig;
34 |
35 |
36 |
37 | /**
38 | * Constructor, Initializes Dependencies and calls the initialization
39 | * method to establish the PDO data connection
40 | *
41 | * @param array $arrDep
42 | * @param string $dbname
43 | * @throws \Exception
44 | */
45 | public function __construct(array $arrDep = array(), $dbname = null)
46 | {
47 | if (empty($arrDep)) {
48 | throw new \Exception('Dependency Failure');
49 | } else {
50 | foreach ($arrDep as $key => $object) {
51 | $this->$key = $object;
52 | }
53 | }
54 | $this->init($dbname);
55 | }
56 |
57 | /**
58 | * Dynamic method handler for basic CRUD functions
59 | *
60 | * Format for dynamic methods names -
61 | * Create: insertTableName($arrData)
62 | * Retrieve: getTableNameByFieldName($value)
63 | * Retrieve all: allTableName()
64 | * Update: updateTableNameByFieldName($value, $arrUpdate)
65 | * Delete: deleteTableNameByFieldName($value)
66 | * Filter (wildcards): filterTableNameByFieldName($value)
67 | *
68 | * @param $method
69 | * @param $params
70 | * @return mixed
71 | */
72 | public function __call($method, $params)
73 | {
74 | $action = substr($method, 0, 3);
75 | $retVal = null;
76 | switch ($action)
77 | {
78 | // Handler for SELECT Statements that do wildcards with an asterisk
79 | case 'fil':
80 | $arr = explode('By', substr($method, 6));
81 | $table = $this->camelCaseToUnderscore($arr[0]);
82 | $field = $this->camelCaseToUnderscore($arr[1]);
83 | $where = $params[0];
84 | $retVal = $this->filter($table, $field, $where);
85 | break;
86 |
87 | // Handler for SELECT Statements
88 | case 'get':
89 | $arr = explode('By', substr($method, 3));
90 | $table = $this->camelCaseToUnderscore($arr[0]);
91 | $field = $this->camelCaseToUnderscore($arr[1]);
92 | $where = $params[0];
93 | $retVal = $this->get($table, $field, $where);
94 | break;
95 |
96 | // Handler for SELECT ALL RECORDS
97 | case 'all':
98 | $table = $this->camelCaseToUnderscore(substr($method, 3));
99 | $retVal = $this->getAll($table);
100 | break;
101 |
102 | // Handler for INSERT Statements
103 | case 'ins':
104 | $table = $this->camelCaseToUnderscore(substr($method, 6));
105 | $arrInsert = $params[0];
106 | $retVal = $this->insert($table, $arrInsert);
107 | break;
108 |
109 | // Handler for UPDATE Statements
110 | case 'upd':
111 | $arr = explode('By', substr($method, 6));
112 | $table = $this->camelCaseToUnderscore($arr[0]);
113 | $where = array($this->camelCaseToUnderscore($arr[1]) => $params[0]);
114 | $set = $params[1];
115 | $retVal = $this->update($table, $set, $where);
116 | break;
117 |
118 | // Handler for DELETE Statements
119 | case 'del':
120 | $arr = explode('By', substr($method, 6));
121 | $table = $this->camelCaseToUnderscore($arr[0]);
122 | $field = $this->camelCaseToUnderscore($arr[1]);
123 | $where = $params[0];
124 | $retVal = $this->delete($table, array($field => $where));
125 | break;
126 | }
127 | return $retVal;
128 | }
129 |
130 | /**
131 | * Initialize a connection to the datasource via PDO
132 | * Switches the connection string based upon the driver being used
133 | *
134 | * @param string $dbname Name of the database (without `db_`) as specified in the config file
135 | * @return PdoConn
136 | * @throws \Exception
137 | *
138 | * @TODO: Add support for adding a custom db driver / dsn string that is compatible with PDO?
139 | */
140 | public function init($dbname = null)
141 | {
142 | $dbname = $this->setDbName($dbname);
143 |
144 | // Load the Connection Configuration
145 | $config = $this->config->item($dbname);
146 |
147 | // Put the Connection Info Into a class property
148 | $this->dbConfig = $config;
149 |
150 | // Build the appropriate connection string
151 | $connStr = $this->createConnectionString($config);
152 |
153 | // Establish a PDO connection or terminate application
154 | try {
155 | $this->conn = new \PDO($connStr, $config['db_user'], $config['db_password']);
156 | return $this;
157 | } catch (\PDOException $e) {
158 | throw new \Exception("data connection error: " . $e->getMessage());
159 | }
160 | }
161 |
162 | /**
163 | * Executes a prepared statement via PDO to return a recordset
164 | * data returned will be as: $array[0]['field_name']
165 | * This script will replace an asterisk with a % sign to allow
166 | * for wildcard searches.
167 | *
168 | * @param $table
169 | * @param $field
170 | * @param $where
171 | * @param null $sort
172 | * @throws \PDOException
173 | * @return mixed
174 | */
175 | public function filter($table, $field, $where, $sort = null)
176 | {
177 | $table = $this->dbConfig['db_prefix'] . $table;
178 |
179 | if (! stristr($where, '*')) {
180 | $where .= '%';
181 | } else {
182 | $where = str_replace('*', '%', $where);
183 | }
184 | $sql = "select * from $table where $field like '$where'";
185 | if (! is_null($sort)) {
186 | $sql .= " ORDER BY $sort";
187 | }
188 |
189 | $stmt = $this->conn->prepare($sql);
190 | if ($stmt === false) {
191 | $err = $this->conn->errorInfo();
192 | throw new \PDOException('Query Failure ['.$err[2].']');
193 | } else {
194 | $stmt->execute();
195 | return $stmt->fetchAll(\PDO::FETCH_ASSOC);
196 | }
197 | }
198 |
199 | /**
200 | * Executes a prepared statement via PDO to return a recordset
201 | * data returned will be as: $array[0]['field_name']
202 | *
203 | * @param $table
204 | * @param $field
205 | * @param $where
206 | * @return mixed
207 | * @throws \PDOException
208 | */
209 | public function get($table, $field, $where)
210 | {
211 | $table = $this->dbConfig['db_prefix'] . $table;
212 |
213 | $stmt = $this->conn->prepare("select * from $table where $field = ?");
214 | $stmt->bindParam(1, $where);
215 |
216 | if ($stmt === false) {
217 | $err = $this->conn->errorInfo();
218 | throw new \PDOException('Query Failure ['.$err[2].']');
219 | } else {
220 | $stmt->execute();
221 | return $stmt->fetchAll(\PDO::FETCH_ASSOC);
222 | }
223 | }
224 |
225 | /**
226 | * Executes a prepared statement via PDO to return a recordset
227 | * data returned will be as: $array[0]['field_name']
228 | * The where clause for this function uses an in statement
229 | *
230 | * @param $table
231 | * @param $field
232 | * @param $where (string containing the in parameters)
233 | * @return mixed
234 | * @throws \PDOException
235 | */
236 | public function getIn($table, $field, $where)
237 | {
238 | $table = $this->dbConfig['db_prefix'] . $table;
239 |
240 | $stmt = $this->conn->prepare("select * from $table where $field in ($where)");
241 | if ($stmt === false) {
242 | $err = $this->conn->errorInfo();
243 | throw new \PDOException('Query Failure ['.$err[2].']');
244 | } else {
245 | $stmt->execute();
246 | return $stmt->fetchAll(\PDO::FETCH_ASSOC);
247 | }
248 | }
249 |
250 | /**
251 | * Executes a prepared statement via PDO to return a recordset
252 | * data returned will be as: $array[0]['field_name']
253 | * This method accepts any valid sql statement
254 | *
255 | * @param $sql
256 | * @return mixed
257 | * @throws \PDOException
258 | */
259 | public function doSql($sql)
260 | {
261 | $stmt = $this->conn->prepare($sql);
262 | if ($stmt === false) {
263 | $err = $this->conn->errorInfo();
264 | throw new \PDOException('Query Failure ['.$err[2].']');
265 | } else {
266 | $stmt->execute();
267 | return $stmt->fetchAll(\PDO::FETCH_ASSOC);
268 | }
269 | }
270 |
271 | /**
272 | * Executes a prepared statement via PDO to return a recordset
273 | * data returned will be as: $array[0]['field_name']
274 | *
275 | * @param string $table table name
276 | * @return array
277 | * @throws \PDOException
278 | */
279 | public function getAll($table)
280 | {
281 | $table = $this->dbConfig['db_prefix'] . $table;
282 |
283 | $stmt = $this->conn->prepare("select * from $table");
284 | if ($stmt === false) {
285 | $err = $this->conn->errorInfo();
286 | throw new \PDOException('Query Failure ['.$err[2].']');
287 | } else {
288 | $stmt->execute();
289 | return $stmt->fetchAll(\PDO::FETCH_ASSOC);
290 | }
291 | }
292 | /**
293 | * Executes a prepared statement via PDO to update the
294 | * database
295 | *
296 | * @param string $table name of database table
297 | * @param array $set set parameters (field => value)
298 | * @param array $where where parameter (field => value)
299 | * @return int affected rows
300 | * @throws \PDOException
301 | */
302 | public function update($table, array $set, array $where)
303 | {
304 | $table = $this->dbConfig['db_prefix'] . $table;
305 |
306 | $i=1;
307 | foreach ($set as $fieldName => $value) {
308 | $arrSet[$i] = "$fieldName = ?";
309 | $param[$i] = $value;
310 | $i++;
311 | }
312 | $strSet = implode(',', $arrSet);
313 | $whereValue = current($where);
314 |
315 | $stmt = $this->conn->prepare('UPDATE '. $table .' SET ' . $strSet . ' WHERE ' . key($where) . ' = ?');
316 |
317 | foreach ($param as $paramNo => &$value) {
318 | $stmt->bindParam($paramNo, $value);
319 | }
320 | $p = count($param);
321 | $stmt->bindParam($p+1, $whereValue);
322 |
323 | if ($stmt === false) {
324 | $err = $this->conn->errorInfo();
325 | throw new \PDOException('Query Failure ['.$err[2].']');
326 | } else {
327 | $stmt->execute();
328 | return $stmt->rowCount();
329 | }
330 | }
331 |
332 | /**
333 | * Executes a prepared statement for PDO to insert a record into the database
334 | * @param string $table
335 | * @param array $arrInsert
336 | * @return int affected rows
337 | * @throws \PDOException
338 | */
339 | public function insert($table, array $arrInsert)
340 | {
341 | $table = $this->dbConfig['db_prefix'] . $table;
342 |
343 | // Build the Fields and Values part of the insert statement
344 | $i=1;
345 | foreach ($arrInsert as $fieldName => $value) {
346 | $fields[] = $fieldName;
347 | $values[$i] = $value;
348 | $param[$i] = '?';
349 | $i++;
350 | }
351 | $strFields = implode(',', $fields);
352 | $strValues = implode(',', $param);
353 |
354 | // Prepare the sql statement
355 | $stmt = $this->conn->prepare('INSERT INTO '.$table.' ('.$strFields.') VALUES ('.$strValues.')');
356 | foreach ($values as $paramNo => &$val) {
357 | $stmt->bindParam($paramNo, $val);
358 | }
359 |
360 | // Execute or throw exception on failure
361 | if ($stmt === false) {
362 | $err = $this->conn->errorInfo();
363 | throw new \PDOException('Query Failure ['.$err[2].']');
364 | } else {
365 | $stmt->execute();
366 | return $this->lastInsertId();
367 | }
368 | }
369 |
370 |
371 | /**
372 | * Execute a prepared statement to delete a record(s) via
373 | * PDO Connection
374 | *
375 | * @param string $table name of table
376 | * @param array $where (field_name => value)
377 | * @return int affected rows
378 | * @throws \PDOException
379 | */
380 | public function delete($table, array $where)
381 | {
382 | $table = $this->dbConfig['db_prefix'] . $table;
383 | $whereValue = current($where);
384 |
385 | $sql = "DELETE FROM $table WHERE " . key($where) . "= ? ";
386 | $stmt = $this->conn->prepare($sql);
387 | $stmt->bindParam(1, $whereValue);
388 |
389 | if ($stmt === false) {
390 | $err = $this->conn->errorInfo();
391 | throw new \PDOException('Query Failure ['.$err[2].']');
392 | } else {
393 | $stmt->execute();
394 | return $stmt->rowCount();
395 | }
396 | }
397 |
398 |
399 | /**
400 | * Changes a camelCase table or field name to lowercase,
401 | * underscore spaced name
402 | *
403 | * @param string $string camelCase string
404 | * @return string underscore_space string
405 | */
406 | public function camelCaseToUnderscore($string)
407 | {
408 | return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $string));
409 | }
410 |
411 | /**
412 | * Builds a connection string based on the database configuration
413 | * @param array $config
414 | * @return string
415 | */
416 | protected function createConnectionString(array $config)
417 | {
418 | // Build the appropriate connection string
419 | switch ($config['driver']) {
420 |
421 | // Connection String for MySQL
422 | case 'mysql':
423 | $connStr = $config['driver'] . ":host=" . $config['host'] . ";dbname=" . $config['db_name'];
424 | if ( $config['port'] !== '') {
425 | $connStr .= ";port=" . $config['port'];
426 | }
427 | break;
428 |
429 | // Connection String for SQL Server 2005 and higher
430 | case 'sqlsrv':
431 | $connStr = $config['driver'] . ":" . $config['dsn'];
432 | break;
433 |
434 | // Connection String for ODBC connections
435 | case 'odbc':
436 | $connStr = $config['driver'] . ":" . $config['dsn'] .";Uid=" . $config['db_user']
437 | . ";Pwd=" . $config['db_password'];
438 | break;
439 |
440 | // Connection String for SQLite
441 | case 'sqlite':
442 | // Set the user & password to blank if there is no config variable set
443 | if (! isset ($config['db_user'])) {
444 | $config['db_user'] = '';
445 | $config['db_password'] = '';
446 | }
447 | $connStr = $config['driver'] . ":" . $config['db_path'] . "/" . $config['db_filename'];
448 | break;
449 |
450 | case 'pgsql':
451 | $connStr = $config['driver'] . ":dbname=" . $config['db_name'] . ";host=" . $config['host'];
452 | if ($config['port'] !== '') {
453 | $connStr .= ";port=" . $config['port'];
454 | }
455 | break;
456 | }
457 | return $connStr;
458 | }
459 |
460 | /**
461 | * Sets the database connection name or default if null
462 | *
463 | * @param null $dbname
464 | * @return string
465 | */
466 | protected function setDbName($dbname = null)
467 | {
468 | if (is_null($dbname)) {
469 | $strDbName = 'db_default';
470 | } else {
471 | $strDbName = 'db_' . $dbname;
472 | }
473 | return $strDbName;
474 | }
475 |
476 | /**
477 | * Returns the ID of the last inserted row or sequence value
478 | *
479 | * @param string $param Name of the sequence object from which the ID should be returned.
480 | * @return string representing the row ID of the last row that was inserted into the database.
481 | */
482 | public function lastInsertId($param = null)
483 | {
484 | return $this->conn->lastInsertId($param);
485 | }
486 | }
487 |
--------------------------------------------------------------------------------