Skip to content

Commit

Permalink
Initial Release
Browse files Browse the repository at this point in the history
  • Loading branch information
codenomdev committed Jul 25, 2020
1 parent f172e30 commit dcd32c3
Show file tree
Hide file tree
Showing 59 changed files with 4,081 additions and 0 deletions.
138 changes: 138 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,140 @@
# codeigniter4-schemas
Database schema management, for CodeIgniter 4

## Quick Start

1. Install with Composer: `> composer require codenom/schemas`
2. Generate a new schema: `> php spark schemas`

## Features

* View your entire database mapped out in a cascading structure
* Read or detect table relationships for easy object-relation mapping (see e.g. [Tatter\Relations](https://github.com/tattersoftware/codeigniter4-relations))
* Get helpful advice on optimizations to your database structure with schema analysis<sup>1</sup>
* Backup, restore, or deploy an entire database structure between servers or environments<sup>1</sup>
* Generate CodeIgniter 4 migration files from an existing database<sup>1</sup>
* Transfer projects to CodeIgniter 4 by reading schema files from other supported formats<sup>1</sup>

<sup>1</sup> Some features are still in development. See **Handlers > Development** for
planned future expansion.

## Installation

Install easily via Composer to take advantage of CodeIgniter 4's autoloading capabilities
and always be up-to-date:
* `> composer require codenom/schemas`

Or, install manually by downloading the source files and adding the directory to
`app/Config/Autoload.php`.

## Configuration (optional)

The library's default behavior can be altered by extending its config file. Copy
**bin/Schemas.php** to **app/Config/** and follow the instructions
in the comments. If no config file is found in **app/Config** the library will use its own.

## Usage

**Schemas** has four main functions, each with a variety of handlers available:
* *Draft*: Generates a new schema from a variety of sources
* *Archive*: Stores a copy of a schema for later use
* *Read*: Loads a schema for live access
* *Publish*: (not yet available) Modifies environments to match schema specs

The **Schemas** service is also available to simplify a workflow with convenient wrapper functions.
At its most basic (with automation enabled), the service will draft, archive, and return
a schema with one simple command:

$schema = service('schemas')->get();

You may want to control when portions of the workflow take place to optimize performance.
Here is an example of one common process, mapping the default database group and storing
the resulting schema to the cache:

```
// Map the database and store the schema in cache
$schemas = service('schemas');
$schemas->draft('database')->archive('cache');
// Load the schema from cache, add Model data, and get the updated schema
$schema = $schemas->read('cache')->draft('model')->get();
```

If you need to deviate from default handler configurations you can inject the handlers yourself:
```
$db = db_connect('alternate_database');
$databaseHandler = new \Codenom\Schemas\Drafter\Handlers\DatabaseHandler(null, $db);
$schema = $schemas->draft($databaseHandler)->get();
```

## Command

**Schemas** comes with a `spark` command for convenient schema generation and display:

`schemas [-draft handler1,handler2,...] [-archive handler1,... | -print]`

Use the command to test and troubleshoot, or add it to your cron for periodic schema caching:

php spark schemas -draft database,model -archive cache

## Automation

By default automation is turned on, but this can be configured via the `$automate` toggles
in your config file. Automation will allow the service to fall back on a Reader, or even on
a Drafter should it fail to have a schema already loaded. While automation makes using the
library very easy, it can come at a performance cost if your application is not configured
correctly, since it may draft a schema on every page load. Use automation to help but don't
let it become a crutch.

## Structure

**Schemas** uses foreign keys, indexes, and naming convention to detect relationships
automatically. Make sure your database is setup using the appropriate keys and
foreign keys to assist with the detection. Naming conventions follow the format of
`{table}_id` for foreign keys and `{table1}_{table2}` for pivot tables. For more examples
on relationship naming conventions consult the Rails Guide
[Active Record Associations](https://guides.rubyonrails.org/association_basics.html#the-types-of-associations)
(and please excuse the Ruby reference).

### Intervention

Should autodetection fail or should you need to deviate from conventions there are a few
tools you can use to overwrite or augment the generated schema.

* **Config/Schemas**: the Config file includes a variable for `$ignoredTables` that will let you skip tables entirely. By default this includes the framework's `migrations` table.
* **app/Schemas/{file}.php**: The `DirectoryHandler` will load any schemas detected in your **Schemas** directory - this gives you a chance to specify anything you want. See [tests/_support/Schemas/Good/Products.php](tests/_support/Schemas/Good/Products.php) for an example.

## Drafting

Currently supported handlers:

* Database
* Model
* PHP
* Directory (PHP import only)

## Archiving/reading

* Cache

## Database Support

All CodeIgniter 4 database drivers work but due to some differences in index handling they
may not all report the same results. Example: see skipped tests for SQLite3.

## Development

The eventual goal is to support mapping from and deploying to any source. Planned handler
implementations include:

* `Publisher\DatabaseHandler`: Recreate a live database from its schema
* `MigrationsHandler`: Create a schema from migration files, or vice versa
* `FileHandler`: A wrapper for importing and exporting from popular schema file formats
* Lots more...

And the file-specific handlers:
* `PhpHandler->archive()`: Create a PHP file with a Schema object in `$schema`
* `XmlHandler`: Support for Doctrine-style XML files
* More to come...

Want to help out? All code and issues are managed on GitHub at [Codenom\Schemas](https://github.com/codenomdev/codeigniter4-schemas)
77 changes: 77 additions & 0 deletions bin/Schemas.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace Config;

/***
*
* This file contains example values to alter default library behavior.
* Recommended usage:
* 1. Copy the file to app/Config/
* 2. Change any values
* 3. Remove any lines to fallback to defaults
*
***/

class Schemas extends \Codenom\Schemas\Config\Schemas
{
// Whether to continue instead of throwing exceptions
public $silent = true;

// Which tasks to automate when a schema is not available from the service
public $automate = [
'draft' => true,
'archive' => true,
'read' => true,
];

//--------------------------------------------------------------------
// Drafting
//--------------------------------------------------------------------

// Default handlers used to create a schema (order sensitive)
// (Probably shouldn't change this unless you really know what you're doing)
public $draftHandlers = [
'Codenom\Schemas\Drafter\Handlers\DatabaseHandler',
'Codenom\Schemas\Drafter\Handlers\ModelHandler',
'Codenom\Schemas\Drafter\Handlers\DirectoryHandler',
];

// Tables to ignore when creating the schema
public $ignoredTables = ['migrations'];

// Namespaces to ignore (mostly for ModelHandler)
public $ignoredNamespaces = [
'Tests\Support',
];

// Path the directoryHandler should scan for schema files
public $schemasDirectory = APPPATH . 'Schemas';

//--------------------------------------------------------------------
// Archiving
//--------------------------------------------------------------------

// Default handlers to archive copies of the schema
public $archiveHandlers = [
'Codenom\Schemas\Archiver\Handlers\CacheHandler',
];

// Default time-to-live for a stored schema (e.g. Cache) in seconds
public $ttl = 14400; // 4 hours

//--------------------------------------------------------------------
// Reading
//--------------------------------------------------------------------

// Default handler used to return and read a schema
public $readHandler = 'Codenom\Schemas\Reader\Handlers\CacheHandler';

//--------------------------------------------------------------------
// Publishing
//--------------------------------------------------------------------

// Precaution to prevent accidental wiping of databases or files
public $safeMode = true;
}

/** End of bin/Schemas.php */
54 changes: 54 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "codenom/schemas",
"description": "Database schema management, for CodeIgniter 4",
"keywords": [
"codeigniter",
"codeigniter4",
"schemas",
"database",
"mapping",
"structure"
],
"homepage": "https://github.com/codenom/codeigniter4-schemas",
"license": "MIT",
"authors": [
{
"name": "Database Schemas for CodeIgniter 4",
"email": "dev@codenom.com",
"homepage": "https://codenom.com",
"role": "Developer"
}
],
"repositories": [
{
"type": "vcs",
"url": "https://github.com/codeigniter4/CodeIgniter4"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": ">=7.2"
},
"require-dev": {
"phpunit/phpunit": "8.5.*",
"mockery/mockery": "^1.0",
"codeigniter4/codeigniter4": "dev-develop"
},
"autoload": {
"psr-4": {
"Codenom\\Schemas\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\Support\\": "tests/_support"
}
},
"scripts": {
"test": "phpunit",
"post-update-cmd": [
"composer dump-autoload"
]
}
}
65 changes: 65 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false">
<testsuites>
<testsuite name="app">
<directory>./tests</directory>
</testsuite>
</testsuites>

<filter>
<whitelist addUncoveredFilesFromWhitelist="true" processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
<exclude>
<directory suffix=".php">./src/Agents</directory>
<directory suffix=".php">./src/Structures</directory>
<directory suffix=".php">./src/Views</directory>
<file>./src/Config/Routes.php</file>
</exclude>
</whitelist>
</filter>

<logging>
<log type="coverage-html" target="build/logs/html"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
<log type="coverage-php" target="build/logs/coverage.serialized"/>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/>
<log type="testdox-html" target="build/logs/testdox.html"/>
<log type="testdox-text" target="build/logs/testdox.txt"/>
<log type="junit" target="build/logs/logfile.xml"/>
</logging>

<php>
<server name="app.baseURL" value="http://example.com"/>

<!-- Directory containing phpunit.xml -->
<const name="HOMEPATH" value="./"/>

<!-- Directory containing the Paths config file -->
<const name="CONFIGPATH" value="./vendor/codeigniter4/codeigniter4/app/Config/"/>

<!-- Directory containing the front controller (index.php) -->
<const name="PUBLICPATH" value="./vendor/codeigniter4/codeigniter4/public/"/>

<!-- https://getcomposer.org/xdebug -->
<env name="COMPOSER_DISABLE_XDEBUG_WARN" value="1"/>

<!-- Database configuration -->
<!-- <env name="database.tests.hostname" value="localhost"/> -->
<!-- <env name="database.tests.database" value="tests"/> -->
<!-- <env name="database.tests.username" value="tests_user"/> -->
<!-- <env name="database.tests.password" value=""/> -->
<!-- <env name="database.tests.DBDriver" value="MySQLi"/> -->
<!-- <env name="database.tests.DBPrefix" value="tests_"/> -->
<env name="database.tests.database" value=":memory:"/>
<env name="database.tests.DBDriver" value="SQLite3"/>
</php>
</phpunit>
50 changes: 50 additions & 0 deletions src/Agents/SchemaAgent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Codenom\Schemas\Agents;

/* Codenom\Agents
* Service analysis and assessment for CodeIgniter 4
* https://github.com/Codenom/codeigniter4-agents
*
* Install:
* `composer require Codenom\agents`
* `php spark handlers:register`
*
* Collect:
* `php spark agents:check`
*
* Monitor:
* https://github.com/Codenom/headquarters
*/

use CodeIgniter\Config\Services;
use Codenom\Agents\BaseAgent;
use Codenom\Agents\Interfaces\AgentInterface;

class SchemaAgent extends BaseAgent implements AgentInterface
{
// Attributes for Codenom\Handlers
public $attributes = [
'name' => 'Schema',
'uid' => 'schema',
'icon' => 'fas fa-project-diagram',
'summary' => 'Map the database structure from the default connection',
];

public function check($path = null)
{
$schemas = Services::schemas();
if (empty($schemas)) {
return false;
}
$config = config('Schemas');

// Generate the schema
$schema = $schemas->import(...$config->defaultHandlers)->get();


$this->record('defaultSchema', 'object', $schema);
}
}

/** End of src/Agents/SchemaAgent.php */
Loading

0 comments on commit dcd32c3

Please sign in to comment.