1. Go to this page and download the library: Download neoan.io/core library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
neoan.io / core example snippets
// A MODEL
...
class User extends Model
{
#[IsPrimary]
public readonly $id;
public ?string $name = null;
#[IsUnique]
public string $email;
public string $job = 'employee';
#[Transform(Hash::class)]
public string $password;
use TimeStamps;
use Setter;
}
// A CONTROLLER
...
$user = new User([
'email'=> '[email protected]',
'name' => 'Someone',
'password' => '123123'
]);
// reconsider name?
$user->name = 'Adam';
$user->store();
...
// or e.g. when updating a password
$user = User::retrieveOne([
'email' => '[email protected]'
]);
// Don't worry! Hashing for this property
// is always ensured by the model
[
'newPassword' => $user->password
] = Request::getInputs();
$user->store();
use Neoan\NeoanApp;
use Neoan\src\Routing\Route;
lo-world')
->inject(['msg' => 'Hello World']);
$app->run();
#!/usr/bin/env php
// the first line is necessary if we don't use the extension ".php"!
// this file load our cli capabilities and is exposed to
// allow advanced users to integrate own commands (based on symfony console)
use App\Config\Config;
use Neoan\Cli\Application;
use Neoan\NeoanApp;
use App\Config\Setup;
use App\Routes\HtmlRoutes;
use Neoan\NeoanApp;
this very script runs
$app = new NeoanApp($srcPath, $publicPath);
new Setup();
new HtmlRoutes();
$app->run();
namespace App\Routes;
class HtmlRoutes {
function __construct()
{
Routes::get('/')->view('home.html');
}
}
namespace App\Config;
use Neoan\Database\Database;
use NeoanIo\MarketPlace\DatabaseAdapter;
use Neoan\Helper\Env;
use Neoan\Response\Response;
use Neoan\Render\Renderer;
class Setup {
function __construct()
{
// Database setup
$dbClient = [
'host' => Env::get('DB_HOST', 'localhost'),
'name' => Env::get('DB_NAME', 'neoan_io'),
'port' => Env::get('DB_PORT', 3306),
'user' => Env::get('DB_USER', 'root'),
'password' => Env::get('DB_PASSWORD', ''),
'charset' => Env::get('DB_CHARSET', 'utf8mb4'),
'casing' => Env::get('DB_CASING', 'camel'),
'assumes_uuid' => Env::get('DB_UUID', false)
];
Database::connect(new DatabaseAdapter($dbClient));
// Defaults
Response::setDefaultOutput(ResponseOutput::HTML);
Renderer::setTemplatePath('src/Views');
}
}
use Neoan\Routing\Route;
Route::request(string $httpMethod, string $endpoint, Routable ...$classes);
use Neoan\Routing\Route;
Route::get(string $endpoint, Routable ...$classes);
use Neoan\Routing\Route;
Route::get('/users/:id')
...
namespace App\Controllers;
use Neoan\Routing\Routable;
class Controller implements Routable
{
public function __invoke(array $provided): array
{
return ["msg" => "Hello World"];
}
}
use Neoan\Routing\Route;
Route::get('/', App\Controllers\Controller::class)
namespace App\Middleware;
use Neoan\Errors\Unauthorized;
use Neoan\Routing\Routable;
use Neoan3\Apps\Stateless;
class NeedsAuth implements Routable
{
public function __invoke(array $provided = []): array
{
try{
return ['auth' => Stateless::validate()];
} catch (\Exception $e) {
new Unauthorized();
}
}
}
use Neoan\Routing\Route;
use App\Middleware\NeedsAuth;
use App\Controllers\Controller;
Route::get('/', NeedsAuth::class, Controller::class)
namespace App\Controllers;
use Neoan\Routing\Routable;
class Controller implements Routable
{
public function __invoke(array $provided): array
{
['auth' => $auth] = $provided;
// better not do that?
return ["token-payload" => $auth];
}
}
use Neoan\Response\Response;
use Neoan\Enums\ResponseOutput;
Response::setDefaultOutput(ResponseOutput::HTML)
use Neoan\Routing\Route;
use Neoan\Response\Response;
use App\Controllers\Controller;
Route::get('/', Controller::class)->response([Response::class,'html']);
// or whatever handler you want:
Route::get('/my-handler', Controller::class)->response([App\Own\MyResponseHandler::class,'answerMethod'])
use Neoan\Routing\Route;
use App\Controllers\Controller;
Route::get('/', Controller::class)->inject(['title'=>'my_app']);
use Neoan\Render\Renderer;
Renderer::setTemplatePath('src/Views');
use Neoan\Routing\Route;
Route::get('/')
->response([Response::class,'html'])
->inject(['user' => ['firstName' => 'Sam']])
->view('/home.html');
// e.g. in idex.php
// ...
$app = new NeoanApp( dirname(__DIR__), __DIR__, dirname(__DIR__));
// invoke using the namespace of whereever your routables are located
$app->invoke(new Neoan\Routing\AttributeRouting('Controller'));
// e.g. Controller\WebRoute.php
namespace Controller;
#[Web('/','/test.html')]
class WebRoute implements Neoan\Routing\Routable
{
public function __invoke(array $provided): array
{
return ["msg" => "Hello World"];
}
}
use Neoan\Render\Renderer;
Renderer::setTemplatePath(string $path);
use Neoan\Render\Renderer;
Renderer::setTemplatePath('src/Views');
use Neoan\Render\Renderer;
Renderer::setHtmlSkeleton(string $templatePath, string $routePlacement, array $renderVariables)
use Neoan\Render\Renderer;
use Neoan\Store\Store;
Renderer::setHtmlSkeleton('src/Views/main.html','routePlacement',[
'title' => Store::dynamic('title'), // 'title' isn't set at this point, so we use the dynamic store
'webPath' => $app->webPath // neoan instance relative webPath in case we need it
])
use Neoan\Routing\Route;
use Neoan\Response\Response;
use Neoan\Enums\ResponseOutput;
use App\YouClass;
Response::setDefaultOutput(ResponseOutput::HTML);
Route::get('/test/:you', YouClass::class)->view('/you.html');
use Neoan\Store\Store;
use Neoan\Routing\Routable;
use Neoan\Request\Request;
class YouClass implements Routable{
public function __invoke(Injections $provided): array
{
Store::write('title','you-route'); // write to dynamic store
return Request::getParams(); // we know this
use Neoan\Event\Event;
use Neoan\Event\Listenable;
use Neoan\Event\EventNotification;
class AnyClass implements Listenable
{
private EventNotification $notifier;
function __construct()
{
$this->notifier = Event::makeListenable($this);
}
function doSomething(string $value)
{
...
$this->notifier->inform($value);
}
}
namespace App\Models;
use Neoan\Model\Model;
use Neoan\Helper\DateHelper;
use Neoan\Model\Attributes\Initialize;
use Neoan\Model\Attributes\IsPrimaryKey;
use Neoan\Model\Attributes\IsUnique;
use Neoan\Model\Attributes\Ignore;
use Neoan\Model\Attributes\Type;
use Neoan\Model\Collection;
use Neoan\Model\Traits\TimeStamps;
class MovieModel extends Model {
// primary keys can either be UUIDS or auto-incremented integers
// as our database setup refused the assumption of UUIDS, integers it is!
// every model needs a primary key, which is indicated by the attribute "IsPrimaryKey"
#[IsPrimaryKey]
public int $id;
// Can there be two movies with the same name? Let's decide no:
// The "IsUnique" attribute let's the auto-migration know that we are serious about this decision.
#[IsUnique]
public string $name;
// Let's go crazy: What if wanted a type that cannot be inferred as it isn't built in?
// We are going to need to worry about two things:
// First, the database type shouldn't default to string (or varchar, in our case),
// so we define it using the "Type" attribute
// Additionally, we would like our model to assume the current date when a model is created,
// so we initialize a Datehelper instance on creation.
#[
Type('date',null),
Initialize(new DateHelper())
]
public string $releaseDate;
// Just to lighten up the attribute-overload, let's create a regular field
// Since it has the type string it will default to a (short-)string data type (e.g. varchar(255)
public string $studio;
// What about relations?
// there is more than one review for a given movie, so we attach ReviewModel instances in a
// collection (see Collections) to the property $reviews based on the ReviewModel's foreign key
// "movieId" which points to our primary key "id"
#[HasMany(ReviewModel::class, ['movieId' => 'id'])]
public Collection $reviews;
// I don't know what I need it for, but the following property is ignored by database transactions
// and only serves for us to store values.
#[Ignore]
public string $aProperty = 'new';
// Traits can be useful to fight repetition. This packaged trait delivers us the properties
// - createdAt (a timestamp filled at creation of the Model)
// - updatedAt (a timestamp that is filled whenever a Model is stored to the database) and
// - deletedAt (a timestamp allowing soft deletion)
use TimeStamps;
}
namespace App\Models;
Neoan\Model\Traits\Setter;
Neoan\Model\Model;
use Neoan\Model\Attributes\IsPrimaryKey;
use Neoan\Model\Attributes\IsForeignKey;
use Neoan\Model\Traits\TimeStamps;
class ReviewModel extends Model{
// Young devs in your team?
// It's probably smart to set the primary key to "readonly" to protect your padawans
// from stupid ideas. However, this fault
#[Type('MEDIUMTEXT', null, 'Awesome')]
public string $content;
// Remember our model "Movie"?
// While we don't need to declare this as foreign key,
// we might want to speed up database queries once our cinema bursts with visitors
#[IsForeignKey]
public int $movieId;
use TimeStamps;
// Want to make your despise for critics known to whoever has to write raw
// queries? Name your table however you like instead of being base on the model name.
const tableName = 'ticks';
}
...
// either initialte with an assoc array
$movie = new MovieModel([
'name' => 'The Matrix'
]);
// or set the individual property
$movie->studio = 'Warner Bros.';
// If you are ready to store the movie to the database (and rehydrate), run store()
$movie->store();
// This will now
...
// The following is NOT recommended in our scenario!
// This is only to show you the possibilities
$movie = new MovieModel();
// will return Neoan\Enums\TransactionType::INSERT
$mode = $move->getTransactionMode();
$movie->setTransactionType(TransactionType::UPDATE);
// sometimes I know the primary id ...
$matrix = MovieModel::get(1);
// ... but often I lookup based on what I know
$matrix = MovieModel::retrieveOne([
'name' => 'The Matrix'
]);
// ... maybe I even want to create it if it doesn't exist
$matix = MovieModel::retrieveOneOrCreate([
'name' => 'The Matrix'
]);
// Let's fix the name
$matix->studio = 'Warner Bros. Pictures'
// Then simply store again
$matrix->store();
...
// First, lets retrieve multiple records
// Instead of "retrieveOne" we will use "retrieve"
// Additionally, we account for soft deleted records and
// want to ignore them by adding a condition to our retrieval
$allMovies = MovieModel::retrieve(['deletedAt' => null]);
// Collections are iterable
foreach($allMovies as $movie){
...
}
// However, it would be a shame if our modern IDE couldn't
// help us with existing properties. So let's use "each" instead
$allMovies->each(function(MovieModel $movie, int $iteration){
...
});
// Did you do something to all the records there?
// Let's save all selected movies at once
$allMovies->store();
// While you can return collections directly,
// you might need to convert them to an array
$flat = $allMovies->toArray();
// Didn't find what you are looking for?
// Just add to the existing collection
$allMovies->add(new MovieModel(['name' => 'Alien']))
...
$currentPage = 1;
$pageSize = 25;
return MovieModel::paginate($currentPage, $pageSize)
// are there conditions/filters to this list?
->where(['studio' => 'Warner Bros. Pictures'])
// controlling the sort
->descending('year')
// finally, execute the pagination request
->get();
[
'page' => 1, // current page
'total' => 50, // total hits
'pageSize' => 30, // number of results per page
'pages' => 2, // total number of resulting pages
'collection' => `{Collection}` // result as Collection
]
#!/usr/bin/env php
...
$console = new Application($app);
$console->add(new MyOwnCommand($app));
...