Initial commit, part due
This commit is contained in:
commit
d750252304
|
@ -0,0 +1,3 @@
|
|||
/vendor/
|
||||
/build/
|
||||
composer.lock
|
|
@ -0,0 +1,66 @@
|
|||
# Mite
|
||||
> The tiniest framework that *mite* work
|
||||
|
||||
*A word of warning, this is an experiment that I'm resurrecting, so it's quite dated atm*
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
/___\ ___ _
|
||||
)O.o( |\/| o | |_ BE small
|
||||
\_^_/ | | | | |_ be STRONG
|
||||
" "
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
**Mite** is a single-file framework that was born out of a necessity of its time, circa 2011, to enable rapid prototyping for PHP. When ideas came too fast to capture in most conventional frameworks for PHP, **Mite** provided a one-include-and-go solution.
|
||||
|
||||
This was also the first time I had the idea to break away from `MVC` structure and just build something based around routing. Turned out this idea was not mine alone, it started with `sinatra.rb`, and continued with `express.js`.
|
||||
|
||||
There are **better options** out there now
|
||||
|
||||
- [FlightPHP](http://flightphp.com/) appears to have achieved my goal
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
### Requirements
|
||||
|
||||
- PHP 5.3+
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Create an `index.php` file and put the following code in it
|
||||
|
||||
```php
|
||||
|
||||
class Prototype extends Mite {
|
||||
|
||||
function index()
|
||||
{
|
||||
// *.tpl.* not required
|
||||
$this->view('index.tpl.php');
|
||||
}
|
||||
}
|
||||
|
||||
$app = new Prototype();
|
||||
$app->route('/', 'index');
|
||||
$app->run();
|
||||
```
|
||||
|
||||
The file name as `index.php` is important for routing
|
||||
|
||||
|
||||
> SEE: `examples/`
|
||||
|
||||
## TODO
|
||||
|
||||
- More Examples
|
||||
- Document API
|
||||
- Modernize (ditch 5.2), but remain small
|
||||
- Mite DB construct take PDO object, not build one
|
||||
- Support REST functionality
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "n2geoff/mite",
|
||||
"description": "single-file php framework for rapid prototyping",
|
||||
"type": "framework",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Geoff Doty",
|
||||
"email": "n2geoff@gmail.com"
|
||||
}
|
||||
],
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"require": {},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php require('../vendor/autoload.php');
|
||||
|
||||
/*
|
||||
* Example: 5.3 OOP Anonymous Functions
|
||||
*/
|
||||
|
||||
$app = new Mite(array('debug' => TRUE, 'index' => '/mite/examples/53oop.php'));
|
||||
|
||||
$app->route('/', function() use($app) {
|
||||
$app->view('views/index.tpl.php');
|
||||
});
|
||||
|
||||
$app->run();
|
|
@ -0,0 +1,16 @@
|
|||
<?php require('../vendor/autoload.php');
|
||||
|
||||
/*
|
||||
* Example: Using MITE as a base class
|
||||
*/
|
||||
class test extends Mite {
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->view('views/index.tpl.php');
|
||||
}
|
||||
}
|
||||
|
||||
$app = new test(array('debug' => TRUE, 'index' => '/mite/examples/extend.php'));
|
||||
$app->route('/', 'index');
|
||||
$app->run();
|
|
@ -0,0 +1,73 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Mite Work</title>
|
||||
<?php echo Mite::style(); ?>
|
||||
<style type="">
|
||||
.main {margin: 0 auto; width: 600px; background-color: #ececec;padding: 10px;}
|
||||
</style>
|
||||
<?php echo Mite::style(); ?>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="dp100">
|
||||
<div style="font-family: monospace; font-size: 1.4em;">
|
||||
<hr/>
|
||||
<h1>MITE</h1>
|
||||
<hr/>
|
||||
./___\.........___ _.................................
|
||||
.)O.o(...|\/|.o.|.|_.....BE small.................... <br/>
|
||||
.\_^_/...|..|.|.|.|_.....be STRONG................... <br/>
|
||||
.."."................................................
|
||||
<hr/>
|
||||
<center>A Rapid Prototyping Micro Framework</center>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dp100">
|
||||
<a href="#">Home</a> | <a href="#">Documentation</a>
|
||||
<hr/>
|
||||
</div>
|
||||
<div class="dp100">
|
||||
<b>MITE</b> is a tiny php framework library designed
|
||||
to enble developers to rapidly prototype out <b>micro ideas</b>.
|
||||
<br/><br/>
|
||||
What are <b>Micro Ideas</b>?
|
||||
<br/><br/>
|
||||
<b>Micro Ideas</b> are things like the developer logging tool
|
||||
<a href="#">logr</a>, or the simple issue tracker <a href="#">taskd</a>
|
||||
<br/><br/>
|
||||
And, just for fun;)
|
||||
</div>
|
||||
<div class="dp100">
|
||||
<h3>Features</h3>
|
||||
<ul>
|
||||
<li>Tiny (under 15k)</li>
|
||||
<li>Portable (single file)</li>
|
||||
<li>Dynamic Named Routes</li>
|
||||
<li>Debugging Profiler</li>
|
||||
<li>Includes a tiny CSS Library</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dp100">
|
||||
<h3>Requirements</h3>
|
||||
<ul>
|
||||
<li>PHP 5.2.x or beyond</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dp100">
|
||||
<h3>Code!</h3>
|
||||
<div style="padding: 10px; background-color: #FFFFFF; border: 1px dashed dimgray;">
|
||||
include 'mite.php';
|
||||
</div>
|
||||
</div>
|
||||
<div class="dp100"><h3><a href="#">Download!</a></h3></div>
|
||||
<div class="dp100">
|
||||
<hr/>
|
||||
<center>©2011 Mite. All rights reserved.</center>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
s
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
forceCoversAnnotation="true"
|
||||
beStrictAboutCoversAnnotation="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
verbose="true">
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
|
@ -0,0 +1,472 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Mite - A Rapid Prototyping Micro Framework
|
||||
*
|
||||
******************************************************************
|
||||
* /___\ ___ _
|
||||
* )O.o( |\/| o | |_ BE small
|
||||
* \_^_/ | | | | |_ be STRONG
|
||||
* " "
|
||||
******************************************************************
|
||||
* @author Geoff Doty <n2geoff@gmail.com>
|
||||
* @version .76
|
||||
*
|
||||
* @copyright 2011 Geoff Doty
|
||||
* @license
|
||||
*/
|
||||
class Mite {
|
||||
|
||||
static private $routes = array(); //route-to-class mapping
|
||||
|
||||
static private $index = '/index.php'; //
|
||||
|
||||
static private $request = NULL; //url in address bar
|
||||
|
||||
// for classes
|
||||
public $callback = NULL; //class/function
|
||||
|
||||
static private $init = NULL; //ah, bad name
|
||||
static public $errors = array(); //bites
|
||||
|
||||
// unused
|
||||
static private $method = NULL; //for RESTish
|
||||
static private $options = array(); //Registry
|
||||
|
||||
// initilizes framework
|
||||
public function __construct($config = array())
|
||||
{
|
||||
$this->init($config);
|
||||
}
|
||||
|
||||
public function init($config = array())
|
||||
{
|
||||
// always set init (can be used as singleton later?)
|
||||
self::$init = microtime(TRUE);
|
||||
|
||||
// sensible defaults
|
||||
$defaults = array
|
||||
(
|
||||
'index' => '/index.php',
|
||||
'debug' => 'FALSE',
|
||||
'paths' => array(
|
||||
'views' => __DIR__,
|
||||
'models' => __DIR__
|
||||
)
|
||||
);
|
||||
|
||||
// merge in configuration overriding defaults
|
||||
self::$options = array_merge($defaults, $config);
|
||||
|
||||
// TODO: ack!!! forgot to update/retrieve settings from options
|
||||
self::$index = self::options('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds route array
|
||||
*
|
||||
* Maps urls to classes or functions
|
||||
*/
|
||||
public function route($url, $callback)
|
||||
{
|
||||
// for dynamic urls
|
||||
$url = preg_replace(array("@\:name@", "@\:id@"), array('([a-zA-Z\_\-]+)','([0-9]+)'), $url);
|
||||
|
||||
self::$routes[$url] = $callback;
|
||||
}
|
||||
|
||||
// TODO: delete/add profile (echo set options)
|
||||
public function _options()
|
||||
{
|
||||
print_r(self::$options);
|
||||
}
|
||||
|
||||
//
|
||||
public function run()
|
||||
{
|
||||
$request = self::uri();
|
||||
|
||||
foreach(self::$routes as $url => $callback)
|
||||
{
|
||||
preg_match("@^{$url}$@", $request, $matches);
|
||||
|
||||
if(isset($matches[0]) && count($matches[0] > 0))
|
||||
{
|
||||
if(is_callable($callback))
|
||||
{
|
||||
return call_user_func($callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
// $class = get_class($this); //5 +
|
||||
// $class = get_called_class(); //5.3
|
||||
|
||||
// if(is_callable("{$class}::{$callback}"))
|
||||
if(is_callable(array($this, $callback)))
|
||||
{
|
||||
// return call_user_func("{$class}::{$callback}"); //called staticly 5.2.3+
|
||||
// return call_user_func(array($class, $callback)); //called?
|
||||
return $this->$callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
echo 'PROBLEM';
|
||||
}
|
||||
// header("HTTP/1.1 404 Not Found");
|
||||
exit('Function Not Found');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// header("HTTP/1.1 404 Not Found");
|
||||
exit('Page Not Found');
|
||||
|
||||
}
|
||||
|
||||
//TODO: index.php required in url should make it either or? hmm htaccess issue
|
||||
public function uri($raw = FALSE)
|
||||
{
|
||||
// cleans and strips query string
|
||||
// $uri = str_replace($this->controller, '', preg_replace('/\?.+/', '', $_SERVER['REQUEST_URI']));
|
||||
$uri = str_replace(self::$index, '', preg_replace('/\?.+/', '', $_SERVER['REQUEST_URI']));
|
||||
|
||||
return ($uri == '' OR $uri == '//') ? '/' : $uri;
|
||||
}
|
||||
|
||||
function options($key = NULL, $value = NULL)
|
||||
{
|
||||
if($key === NULL)
|
||||
{
|
||||
return self::$options;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($value === NULL)
|
||||
{
|
||||
return $option = isset(self::$options[$key]) ? self::$options[$key] : NULL ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $option = isset(self::$options[$key][$value]) ? self::$options[$key][$value] : NULL ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* State Management
|
||||
*****************************************************************/
|
||||
/**
|
||||
* Cookie Managment
|
||||
*
|
||||
* set/get cookies by call signature
|
||||
*/
|
||||
public function cookie($name, $value = NULL, $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly=false)
|
||||
{
|
||||
if($value === NULL)
|
||||
{ // read cookie
|
||||
return $cookie = isset($_COOKIE[$name]) ? $_COOKIE[$name] : NULL ;
|
||||
}
|
||||
else
|
||||
{ // create cookie
|
||||
setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flash Notice
|
||||
*
|
||||
* Creates cookie expires on next request
|
||||
*/
|
||||
public function flash($name, $value)
|
||||
{
|
||||
self::cookie($name, $value, $expire = time()+1);
|
||||
}
|
||||
|
||||
public function session($key, $value = NULL)
|
||||
{
|
||||
if($value === NULL)
|
||||
{ // read session
|
||||
return $session = isset($_SESSION[$name]) ? $_SESSION[$name] : NULL ;
|
||||
}
|
||||
else
|
||||
{ // create session
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* Helper Methods
|
||||
*****************************************************************/
|
||||
|
||||
/**
|
||||
* Return Uri Segment
|
||||
*/
|
||||
public function uri_segment($number)
|
||||
{
|
||||
$segments = explode('/', trim(self::$request, '/'));
|
||||
|
||||
return $segment = isset($segments[($number - 1)]) ? $segments[($number - 1)] : NULL;
|
||||
}
|
||||
|
||||
public function input($key, $clean = TRUE)
|
||||
{ // merge global input arrays
|
||||
$input = array_merge($_GET, $_POST);
|
||||
|
||||
if($clean === TRUE)
|
||||
{
|
||||
return isset($input[$key]) ? self::xss($input[$key]) : NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return isset($input[$key]) ? $input[$key] : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public function xss($value)
|
||||
{
|
||||
$value = stripslashes($value);
|
||||
return htmlentities($value);
|
||||
}
|
||||
|
||||
public function style($file = NULL)
|
||||
{
|
||||
if($file === NULL)
|
||||
{
|
||||
$style = "<style type='text/css'>\n";
|
||||
$style .= "\t html,body,div,p{margin:0;padding:0;border:0;}";
|
||||
// $style .= ".main{margin: 0 auto; width: 600px;}";
|
||||
$style .= ".profile{background-color: #e3e3e3;font-weight: bold; border-bottom: 1px solid #404040;}";
|
||||
$style .= ".dp20,.dp25,.dp33,.dp50,.dp100{float:left;display:inline;*margin-left:-0.04em;}";
|
||||
$style .= ".dp20{width:20%;}.dp25{width:25%;}.dp33{width:33.33%;}.dp50{width:50%;}.dp100{width:100%;}";
|
||||
$style .= ".clear{clear:both;}";
|
||||
$style .= "\n</style>\n";
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
public function view($template, $data = NULL)
|
||||
{
|
||||
if($data != NULL)
|
||||
{
|
||||
if(is_array($data))
|
||||
{
|
||||
extract($data);
|
||||
}
|
||||
}
|
||||
|
||||
$dir = self::options('paths','views');
|
||||
|
||||
include("{$dir}/{$template}");
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* Error Handling and Logging
|
||||
*****************************************************************/
|
||||
|
||||
public function errors() {}
|
||||
protected function has_error()
|
||||
{
|
||||
if(count(self::$errors) > 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
public function log($message) {}
|
||||
|
||||
/*****************************************************************
|
||||
* Profiling
|
||||
*****************************************************************/
|
||||
|
||||
function explain()
|
||||
{
|
||||
$output = "\n<!-- Debugging Information -->\n";
|
||||
$output .= Mite::style();
|
||||
|
||||
$output .= "<div class='main'>\n";
|
||||
$output .= "<fieldset>\n\t<legend>Debugging Information</legend>\n";
|
||||
|
||||
// Routing
|
||||
$output .= "<div class='dp100 profile'>\n";
|
||||
$output .= "\t<div class='dp33'><b>PAGE REQUEST</b></div>\n";
|
||||
$output .= "\t<div class='dp33'>" . self::uri() . "</div>\n";
|
||||
$output .= "\t<div class='dp33'> </div>\n";
|
||||
$output .= "</div>\n";
|
||||
|
||||
$output .= "<div class='dp100'>\n";
|
||||
foreach(self::$routes as $route => $callback)
|
||||
{
|
||||
$output .= "\t<div class='dp33'> </div>\n"; // future request method
|
||||
$output .= "\t<div class='dp33'>{$route}</div>\n";
|
||||
$output .= "\t<div class='dp33'>";
|
||||
$output .= is_object($callback) ? get_class($callback) : $callback;
|
||||
$output .= "</div>\n";
|
||||
}
|
||||
$output .= "</div>\n";
|
||||
|
||||
// Request varibles
|
||||
$output .= "<div class='dp100 profile'>GET DATA</div>\n";
|
||||
foreach($_GET as $key => $value)
|
||||
{
|
||||
$output .= "\t<div class='dp50'>{$key}</div>\n";
|
||||
$output .= "\t<div class='dp50'>{$value}</div>\n";
|
||||
}
|
||||
|
||||
$output .= "<div class='dp100 profile'>POST DATA</div>\n";
|
||||
foreach($_POST as $key => $value)
|
||||
{
|
||||
$output .= "\t<div class='dp50'>{$key}</div>\n";
|
||||
$output .= "\t<div class='dp50'>{$value}</div>\n";
|
||||
}
|
||||
|
||||
$output .= "<div class='dp100 profile'>COOKIE DATA</div>\n";
|
||||
foreach($_COOKIE as $key => $value)
|
||||
{
|
||||
$output .= "\t<div class='dp50'>{$key}</div>\n";
|
||||
$output .= "\t<div class='dp50'>{$value}</div>\n";
|
||||
}
|
||||
|
||||
$output .= "<div class='dp100 profile'>SESSION DATA</div>\n";
|
||||
if(isset($_SESSION))
|
||||
{
|
||||
foreach((array) $_SESSION as $key => $value)
|
||||
{
|
||||
$output .= "\t<div class='dp50'>{$key}</div>\n";
|
||||
$output .= "\t<div class='dp50'>{$value}</div>\n";
|
||||
}
|
||||
}
|
||||
|
||||
// continued in __destruct()
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if(self::options('debug') === TRUE)
|
||||
{
|
||||
$output = self::explain();
|
||||
|
||||
// Memory
|
||||
$output .= "<div class='dp100 profile'>MEMORY USAGE</div>\n";
|
||||
$output .= "\t<div class='dp33'> </div>\n";
|
||||
$output .= "\t<div class='dp33'>" . round(memory_get_usage()/1024,2) . " KBs</div>\n";
|
||||
$output .= "\t<div class='dp33'>" . round(memory_get_peak_usage()/1024,2) . " KBs</div>\n";
|
||||
// $output .= "</div>\n";
|
||||
|
||||
// Profiling
|
||||
$output .= "<div class='dp100 profile'>PROFILING USAGE</div>\n";
|
||||
$output .= "\t<div class='dp50'> </div>\n";
|
||||
$output .= "\t<div class='dp50'>" . round(microtime(true) - self::$init, 4) . " Seconds</div>\n";
|
||||
// $output .= "</div>\n";
|
||||
|
||||
$output .= "</fieldset>\n</div>\n";
|
||||
$output .= "\n<!-- End of Debugging Information -->\n";
|
||||
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Basic CRUD class, may remove, or make more query builder style
|
||||
abstract class Mite_Model {
|
||||
|
||||
protected $_table; // table name
|
||||
protected $_key; // primary key
|
||||
private $db;
|
||||
|
||||
public function __construct($dsn, $username = NULL, $password = NULL)
|
||||
{
|
||||
$this->db = $this->connect($dsn, $username, $password);
|
||||
}
|
||||
|
||||
public function connect($dsn, $username = NULL, $password = NULL)
|
||||
{
|
||||
// $dsn = "{$driver}:dbname={$database};host={$host}";
|
||||
|
||||
try
|
||||
{
|
||||
return new PDO($dsn, $username, $password);
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// basic crud
|
||||
public function insert($data)
|
||||
{
|
||||
$sql = "INSERT INTO {$this->_table} ";
|
||||
|
||||
$columns = array();
|
||||
$values = array();
|
||||
foreach($data as $column => $value)
|
||||
{
|
||||
$columns[] = $column;
|
||||
$values[] = $value;
|
||||
}
|
||||
|
||||
$sql .= '(' . implode(',', $columns) . ') ';
|
||||
$sql .= 'VALUES(' . implode(',', $values) . ')';
|
||||
|
||||
return $this->db->exec($sql);
|
||||
}
|
||||
|
||||
public function update($data)
|
||||
{
|
||||
$sql = "UPDATE {$this->_table} SET ";
|
||||
|
||||
$updates = array();
|
||||
foreach($data as $column => $value)
|
||||
{
|
||||
$updates[] = "{$column}='{$value}'";
|
||||
}
|
||||
|
||||
$sql .= implode(',', $updates);
|
||||
$sql .= "WHERE {$this->_key}='{$value[$this->_key]}'";
|
||||
|
||||
return $this->db->exec($sql);
|
||||
}
|
||||
|
||||
public function delete($data)
|
||||
{
|
||||
$sql = "DELETE FROM {$this->_table} ";
|
||||
|
||||
$deletes = array();
|
||||
foreach($data as $column => $value)
|
||||
{
|
||||
$deletes[] = "{$column}='{$value}'";
|
||||
}
|
||||
|
||||
$sql .= implode(',', $deletes);
|
||||
$sql .= "WHERE {$column}='{$value}'";
|
||||
|
||||
return $this->db->exec($sql);
|
||||
}
|
||||
|
||||
public function find($value)
|
||||
{
|
||||
$sql = "SELECT * FROM {$this->_table} WHERE {$this->_key} = '{$value}'";
|
||||
return $this->db->query($sql);
|
||||
}
|
||||
|
||||
// raw sql
|
||||
public function query($sql)
|
||||
{
|
||||
return $this->db->query($sql);
|
||||
}
|
||||
|
||||
public function last_id()
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
catch(PDOException $e)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MiteTest extends TestCase {
|
||||
|
||||
public function testMiteExist() {
|
||||
$mite = new Mite();
|
||||
|
||||
$this->assertInstanceOf('Mite', $mite);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue