diff --git a/src/Yuga/Application/Application.php b/src/Yuga/Application/Application.php index 4da789f..6ec07d5 100644 --- a/src/Yuga/Application/Application.php +++ b/src/Yuga/Application/Application.php @@ -24,7 +24,7 @@ class Application extends Container implements IApplication { - const VERSION = '3.2.0'; + const VERSION = '3.3.0'; const CHARSET_UTF8 = 'UTF-8'; /** @@ -417,9 +417,4 @@ public function terminate() { exit(0); } - - public function __destruct() - { - $this->get('events')->dispatch('on:app-stop'); - } } \ No newline at end of file diff --git a/src/Yuga/Authenticate/Authenticate.php b/src/Yuga/Authenticate/Authenticate.php index c6ebf52..326bec7 100644 --- a/src/Yuga/Authenticate/Authenticate.php +++ b/src/Yuga/Authenticate/Authenticate.php @@ -88,7 +88,7 @@ public function guest() public function run(Request $request, Closure $next) { if ($this->guest()) { - return (\Auth::authRoutesExist()) ? $this->response->redirect->route('login') : $this->response->redirect->to(env('DEFAULT_LOGIN_REDIRECT', '/login')); + return (\Auth::authRoutesExist()) ? $this->response->redirect->route('login') : $this->response->redirect->to(env('DEFAULT_LOGIN_REDIRECT', route('/login'))); die(); } diff --git a/src/Yuga/Authenticate/LoginWithRemember.php b/src/Yuga/Authenticate/LoginWithRemember.php index 347d51d..19b5975 100755 --- a/src/Yuga/Authenticate/LoginWithRemember.php +++ b/src/Yuga/Authenticate/LoginWithRemember.php @@ -40,9 +40,9 @@ public function __construct(Session $session, Cookie $cookie, User $user, Applic public function run(Request $request, Closure $next) { $settings = $this->app->config->load('config.Settings'); - if($this->cookie->exists($settings->get('remember.name')) && !$this->session->isLoggedIn()){ + if($this->cookie->exists($settings->get('remember.name')) && !$this->session->isLoggedIn()) { $hash = $this->cookie->get($settings->get('remember.name')); - if($hashCheck = $this->user->where('remember_token', $hash)->first()){ + if($hashCheck = $this->user->where('remember_token', $hash)->first()) { $this->session->login($hashCheck); } } diff --git a/src/Yuga/Database/Elegant/Builder.php b/src/Yuga/Database/Elegant/Builder.php index 2f5785d..186269f 100644 --- a/src/Yuga/Database/Elegant/Builder.php +++ b/src/Yuga/Database/Elegant/Builder.php @@ -1049,7 +1049,7 @@ public function datatable($length = 10, $draw = null, $pageName = 'draw', $pathN $orderable = []; foreach ($columns as $column) { - if ((bool)$column['searchable'] === 'true') { + if ($column['searchable'] === 'true') { if (!in_array($column['data'], $this->getModel()->bootable)) $searchable[] = $column['data']; } @@ -1067,7 +1067,7 @@ public function datatable($length = 10, $draw = null, $pageName = 'draw', $pathN if (count($orderBy) > 0) { foreach ($orderBy as $filterI => $filter) { $column = $columns[$filter['column']]; - if ((bool)$column['orderable'] === 'true') { + if ($column['orderable'] === 'true') { if (!in_array($column['data'], $this->getModel()->bootable)) $orderable[$column['data']] = $filter['dir']; } diff --git a/src/Yuga/Database/Elegant/Model.php b/src/Yuga/Database/Elegant/Model.php index 511a800..a5f4caf 100644 --- a/src/Yuga/Database/Elegant/Model.php +++ b/src/Yuga/Database/Elegant/Model.php @@ -732,17 +732,52 @@ public function newFromQuery($attributes = [], array $bootable = null, array $it } if (count($this->cast) > 0) { - foreach ($model->cast as $attribute => $type) { - if (in_array($attribute, array_keys($model->attributes))) { - $attributeData = $model->attributes[$attribute]; + $model = $this->castTo($model); + } + return $model; + } + + protected function castTo(Model $model) + { + foreach ($model->cast as $attribute => $type) { + if (in_array($attribute, array_keys($model->attributes))) { + $attributeData = $model->attributes[$attribute]; + + if ($type == 'array') { + $attributeData = $this->castToArray($attributeData); + } else if ($type == 'json' || $type == 'json-array') { + $attributeData = $this->castToJson($attributeData); + } else { settype($attributeData, $type); - $model->setAttribute($attribute, $attributeData); } + $model->setAttribute($attribute, $attributeData); } } + return $model; } + protected function isJson(?string $string = null) + { + json_decode($string ?? null); + return json_last_error() === JSON_ERROR_NONE; + } + + protected function castToArray(string $string) + { + if ($this->isJson($string)) + $string = json_decode($string, true); + else + $string = (array)$string; + + return $string; + } + + protected function castToJson($array) + { + return json_encode($array); + } + /** * Invoke funtions or return strings or arrays that functions return * diff --git a/src/Yuga/Database/Migration/MigrationServiceProvider.php b/src/Yuga/Database/Migration/MigrationServiceProvider.php index 8ca82c6..b050f51 100755 --- a/src/Yuga/Database/Migration/MigrationServiceProvider.php +++ b/src/Yuga/Database/Migration/MigrationServiceProvider.php @@ -68,6 +68,30 @@ protected function rollBackMigrations($migrations) } } + public function seed(Application $app) + { + $config = $app->config->load('config.migrations'); + + if ($app->runningInConsole()) { + if (count($config->get('migrate')) > 0) { + foreach (glob($this->getMigrationPath()."*.php") as $migration) { + require_once $migration; + } + $this->runSeeders($config->get('migrate')); + } + } + } + + protected function runSeeders($migrations) + { + foreach ($migrations as $migration) { + if (class_exists($migration)) { + $migration = new $migration; + $migration->seeder(); + } + } + } + protected function getMigrationPath() { return path().'database'.DIRECTORY_SEPARATOR.'migrations'.DIRECTORY_SEPARATOR; diff --git a/src/Yuga/Database/Migration/Schema/Pgsql/Column.php b/src/Yuga/Database/Migration/Schema/Pgsql/Column.php index 8b13f51..a5593f0 100755 --- a/src/Yuga/Database/Migration/Schema/Pgsql/Column.php +++ b/src/Yuga/Database/Migration/Schema/Pgsql/Column.php @@ -22,7 +22,7 @@ class Column const INDEX_PRIMARY = 'PRIMARY KEY'; const INDEX_UNIQUE = 'UNIQUE'; - const INDEX_INDEX = 'INDEX'; + const INDEX_INDEX = null; const INDEX_FULLTEXT = 'FULLTEXT'; const RELATION_TYPE_RESTRICT = 'RESTRICT'; @@ -31,8 +31,9 @@ class Column const RELATION_TYPE_NO_ACTION = 'NO ACTION'; const TYPE_VARCHAR = 'VARCHAR'; - const TYPE_LONGTEXT = 'LONGTEXT'; + const TYPE_LONGTEXT = 'TEXT'; const TYPE_TEXT = 'TEXT'; + const TYPE_TEXT_ARRAY = 'TEXT[]'; const TYPE_MEDIUMTEXT = 'MEDIUMTEXT'; const TYPE_TINYTEXT = 'TINYTEXT'; const TYPE_INTEGER = 'INTEGER'; @@ -81,6 +82,7 @@ class Column self::TYPE_VARCHAR, self::TYPE_LONGTEXT, self::TYPE_TEXT, + self::TYPE_TEXT_ARRAY, self::TYPE_MEDIUMTEXT, self::TYPE_TINYTEXT, self::TYPE_INTEGER, @@ -227,7 +229,7 @@ public function setIndex($index) public function getIndex() { - return $this->index; + return $this->index ? : null; } public function setIncrement($increment) @@ -373,6 +375,13 @@ public function longtext() return $this; } + public function textarray() + { + $this->setType(self::TYPE_TEXT_ARRAY); + + return $this; + } + public function datetime() { $this->setType(self::TYPE_DATETIME); @@ -474,7 +483,7 @@ public function getQuery($includeRelations = true) $query = sprintf('"%s" %s%s %s', $this->getName(), $this->getType(), $length, $this->getAttributes()); - $query .= (!$this->getNullable()) ? 'NOT null' : 'null'; + $query .= (!$this->getNullable()) ? 'NOT Null' : 'DEFAULT Null'; if ($this->getDefaultValue()) { $query .= PdoHelper::formatQuery(' DEFAULT %s', [$this->getDefaultValue()]); diff --git a/src/Yuga/Models/Console/CanCreate.php b/src/Yuga/Models/Console/CanCreate.php index ecc3a1f..46d1f0f 100644 --- a/src/Yuga/Models/Console/CanCreate.php +++ b/src/Yuga/Models/Console/CanCreate.php @@ -8,20 +8,35 @@ trait CanCreate { + /** + * Make the scaffold for a create form + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ protected function makeCreateForm(Model $model) { $name = \class_base($model); $inputs = ""; $property = \strtolower($name); + $isEditor = false; + $editors = 0; + foreach ($model->scaffold as $fieldName => $type) { $fieldType = Scaffold::getFormType($type); - $input = ''; + $input = ''; if ($fieldType != 'password') { - $input = ''; + $input = ''; } if ($fieldType == 'textarea') { - $input = ''; + $input = ''; + } + + if ($fieldType == 'editor') { + $isEditor = true; + $input = ''; + $editors += 1; } $label = \ucfirst($fieldName); @@ -33,14 +48,28 @@ protected function makeCreateForm(Model $model) @endif ' . "\n\t\t\t\t"; } + + $script = ""; + if ($isEditor) { + $element = ($editors > 1) ? ".editor" : "#editor"; + + $script = " + + + "; + } $directory = path('resources/views/' . $property); if (!is_dir($directory)) { mkdir($directory, 0755, true); } $creator = str_replace( - ['{title}', '{inputs}', '{form-title}', '{route}'], - [$name, $inputs, 'Create', Inflect::pluralize($property)], + ['{title}', '{inputs}', '{form-title}', '{route}', '{scripts}'], + [$name, $inputs, 'Create', Inflect::pluralize($property), $script], file_get_contents(__DIR__.'/temps/scaffold/create-form.temp') ); $fileName = $directory . '/create.hax.php'; diff --git a/src/Yuga/Models/Console/CanDelete.php b/src/Yuga/Models/Console/CanDelete.php index 9e991a8..9bea7df 100644 --- a/src/Yuga/Models/Console/CanDelete.php +++ b/src/Yuga/Models/Console/CanDelete.php @@ -2,7 +2,49 @@ namespace Yuga\Models\Console; +use Yuga\Support\Inflect; +use Yuga\Scaffold\Scaffold; +use Yuga\Database\Elegant\Model; + trait CanDelete { - + /** + * Make the scaffold for a delete form + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ + public function makeDeleteForm(Model $model) + { + $name = \class_base($model); + $inputs = ""; + $property = \strtolower($name); + foreach ($model->scaffold as $fieldName => $type) { + + $fieldType = Scaffold::getFormType($type); + + $label = \ucfirst($fieldName); + if ($fieldType != 'password') { + $inputs .= '
'. str_replace('_', ' ', $label) .'
{{ $' . $property . '->' . $fieldName . ' }}
' . "\n\t\t\t"; + } + } + + $directory = path('resources/views/' . $property); + if (!is_dir($directory)) { + mkdir($directory, 0755, true); + } + $creator = str_replace( + ['{title}', '{form}', '{model-id}', '{route}'], + [$name, $inputs, '$' . $property . '->' . $model->getPrimaryKey(), Inflect::pluralize($property)], + file_get_contents(__DIR__.'/temps/scaffold/delete.temp') + ); + $fileName = $directory . '/delete.hax.php'; + if (file_exists($fileName) && !$this->option('force')) { + if ($this->confirm("The [{$fileName}] view already exists. Do you want to replace it?")) { + file_put_contents($fileName, $creator); + } + } else { + file_put_contents($fileName, $creator); + } + } } \ No newline at end of file diff --git a/src/Yuga/Models/Console/CanDisplay.php b/src/Yuga/Models/Console/CanDisplay.php index ddeb386..c69831f 100644 --- a/src/Yuga/Models/Console/CanDisplay.php +++ b/src/Yuga/Models/Console/CanDisplay.php @@ -8,6 +8,12 @@ trait CanDisplay { + /** + * Make the scaffold for a Index page + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ protected function makeIndexForm(Model $model) { $name = \class_base($model); diff --git a/src/Yuga/Models/Console/CanShowDetails.php b/src/Yuga/Models/Console/CanShowDetails.php index c58372c..dba9c30 100644 --- a/src/Yuga/Models/Console/CanShowDetails.php +++ b/src/Yuga/Models/Console/CanShowDetails.php @@ -8,6 +8,11 @@ trait CanShowDetails { + /** + * Make the scaffold for a details form + * + * @param \Yuga\Database\Elegant\Model $model + */ protected function makeDetailsForm(Model $model) { $name = \class_base($model); @@ -15,13 +20,11 @@ protected function makeDetailsForm(Model $model) $property = \strtolower($name); foreach ($model->scaffold as $fieldName => $type) { - - $fieldType = Scaffold::getFormType($type); $label = \ucfirst($fieldName); if ($fieldType != 'password') { - $inputs .= '
'. str_replace('_', ' ', $label) .'
{{ $' . $property . '->' . $fieldName . ' }}
' . "\n\t\t\t"; + $inputs .= '
'. str_replace('_', ' ', $label) .'
{{ $' . $property . '->' . $fieldName . ' }}
' . "\n\t\t\t"; } } diff --git a/src/Yuga/Models/Console/CanUpdate.php b/src/Yuga/Models/Console/CanUpdate.php index 1dfddf0..92c3f83 100644 --- a/src/Yuga/Models/Console/CanUpdate.php +++ b/src/Yuga/Models/Console/CanUpdate.php @@ -8,26 +8,40 @@ trait CanUpdate { + /** + * Make the scaffold for a update form + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ protected function makeUpdateForm(Model $model) { $name = \class_base($model); $inputs = ""; $property = \strtolower($name); - foreach ($model->scaffold as $fieldName => $type) { + $isEditor = false; + $editors = 0; + foreach ($model->scaffold as $fieldName => $type) { $fieldType = Scaffold::getFormType($type); - $input = ''; + $input = ''; if ($fieldType != 'password') { - $input = ''; + $input = ''; } if ($fieldType == 'textarea') { - $input = ''; + $input = ''; + } + + if ($fieldType == 'editor') { + $isEditor = true; + $input = ''; + $editors += 1; } $label = \ucfirst($fieldName); $inputs .= '
- + ' . $input . ' @if($errors->has("'. $fieldName .'")) {{ $errors->first("'. $fieldName .'") }} @@ -35,13 +49,27 @@ protected function makeUpdateForm(Model $model)
' . "\n\t\t\t\t"; } + $script = ""; + if ($isEditor) { + $element = ($editors > 1) ? ".editor" : "#editor"; + + $script = " + + + "; + } + $directory = path('resources/views/' . $property); if (!is_dir($directory)) { mkdir($directory, 0755, true); } $creator = str_replace( - ['{title}', '{inputs}', '{form-title}', '{route}'], - [$name, $inputs, 'Edit', Inflect::pluralize($property)], + ['{title}', '{inputs}', '{form-title}', '{route}', '{scripts}'], + [$name, $inputs, 'Edit', Inflect::pluralize($property), $script], file_get_contents(__DIR__.'/temps/scaffold/create-form.temp') ); $fileName = $directory . '/edit.hax.php'; diff --git a/src/Yuga/Models/Console/CreateControllers.php b/src/Yuga/Models/Console/CreateControllers.php index dc4972f..3ac1e50 100644 --- a/src/Yuga/Models/Console/CreateControllers.php +++ b/src/Yuga/Models/Console/CreateControllers.php @@ -7,6 +7,12 @@ trait CreateControllers { + /** + * Make the scaffold for a controller + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ protected function processControllers(Model $model) { $name = \class_base($model); diff --git a/src/Yuga/Models/Console/CreateMigrations.php b/src/Yuga/Models/Console/CreateMigrations.php index ba39f51..3c20e83 100644 --- a/src/Yuga/Models/Console/CreateMigrations.php +++ b/src/Yuga/Models/Console/CreateMigrations.php @@ -8,6 +8,12 @@ trait CreateMigrations { + /** + * Make the scaffold for migrations + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ protected function processMigrations(Model $model) { $name = \class_base($model); diff --git a/src/Yuga/Models/Console/CreateRoutes.php b/src/Yuga/Models/Console/CreateRoutes.php index 42fd303..dd09795 100644 --- a/src/Yuga/Models/Console/CreateRoutes.php +++ b/src/Yuga/Models/Console/CreateRoutes.php @@ -7,6 +7,12 @@ trait CreateRoutes { + /** + * Make the scaffold for a routes + * + * @param \Yuga\Database\Elegant\Model $model + * @param mixed + */ protected function processRoutes(Model $model) { $name = \class_base($model); diff --git a/src/Yuga/Models/Console/MakeScaffoldCommand.php b/src/Yuga/Models/Console/MakeScaffoldCommand.php index fec8e6e..e6b9ae1 100644 --- a/src/Yuga/Models/Console/MakeScaffoldCommand.php +++ b/src/Yuga/Models/Console/MakeScaffoldCommand.php @@ -63,6 +63,7 @@ protected function formsCreator(array $models = []) // make all the index pages $this->makeIndexForm($modelInstance); // make all the delete pages + $this->makeDeleteForm($modelInstance); // process routes $this->processRoutes($modelInstance); // process controllers diff --git a/src/Yuga/Models/Console/temps/scaffold/create-form.temp b/src/Yuga/Models/Console/temps/scaffold/create-form.temp index 504f74f..e3737f2 100644 --- a/src/Yuga/Models/Console/temps/scaffold/create-form.temp +++ b/src/Yuga/Models/Console/temps/scaffold/create-form.temp @@ -26,4 +26,8 @@
Back to List
+@endsection + +@section('scripts') + {scripts} @endsection \ No newline at end of file diff --git a/src/Yuga/Models/Console/temps/scaffold/delete.temp b/src/Yuga/Models/Console/temps/scaffold/delete.temp new file mode 100644 index 0000000..8feb0b8 --- /dev/null +++ b/src/Yuga/Models/Console/temps/scaffold/delete.temp @@ -0,0 +1,20 @@ +@extends('layouts.app') + +@section('content') +

Delete

+ +

Are you sure you want to delete this?

+
+

{title}

+
+
+ {form} +
+ +
+ {{ token() }} + | + Back to List +
+
+@endsection \ No newline at end of file diff --git a/src/Yuga/Models/Console/temps/scaffold/details.temp b/src/Yuga/Models/Console/temps/scaffold/details.temp index 85bdf70..097e078 100644 --- a/src/Yuga/Models/Console/temps/scaffold/details.temp +++ b/src/Yuga/Models/Console/temps/scaffold/details.temp @@ -6,9 +6,9 @@

{title}


-
+
{form} -
+
Edit | diff --git a/src/Yuga/Route/Exceptions/NotFoundHttpControllerException.php b/src/Yuga/Route/Exceptions/NotFoundHttpControllerException.php new file mode 100644 index 0000000..b6825c2 --- /dev/null +++ b/src/Yuga/Route/Exceptions/NotFoundHttpControllerException.php @@ -0,0 +1,7 @@ +handleException(new NotFoundHttpException($message, 404)); + $this->handleException(new NotFoundHttpMethodException($message, 404)); } } else { $message = sprintf('Controller: "%s" not found', $controller); - $this->handleException(new NotFoundHttpException($message, 404)); + $this->handleException(new NotFoundHttpControllerException($message, 404)); } } diff --git a/src/Yuga/Route/Router/Route.php b/src/Yuga/Route/Router/Route.php index b8e8e37..fad1174 100755 --- a/src/Yuga/Route/Router/Route.php +++ b/src/Yuga/Route/Router/Route.php @@ -13,7 +13,9 @@ use Yuga\Http\Middleware\IMiddleware; use Yuga\Route\Exceptions\HttpException; use Yuga\Route\Exceptions\NotFoundHttpException; +use Yuga\Route\Exceptions\NotFoundHttpMethodException; use Yuga\Http\Middleware\MiddleWare as RouteMiddleware; +use Yuga\Route\Exceptions\NotFoundHttpControllerException; use Yuga\Database\Elegant\Exceptions\ModelNotFoundException; abstract class Route implements IRoute @@ -62,13 +64,19 @@ abstract class Route implements IRoute protected function loadClass($name) { - - // if (is_string($name)) { - if (class_exists($name) === false) { - throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $name), 404); + $exception = NotFoundHttpException::class; + if (env('DEBUG_MODE_SETTINGS', '{"controller_missing": true, "method_missing": true}') != null) { + $debugSettings = json_decode(env('DEBUG_MODE_SETTINGS', '{"controller_missing": true, "method_missing": true}'), true); + if (isset($debugSettings['controller_missing'])) { + if ($debugSettings['controller_missing'] === true) { + $exception = NotFoundHttpControllerException::class; + } } - return Application::getInstance()->resolve($name); - + } + if (class_exists($name) === false) { + throw new $exception(sprintf('Class "%s" does not exist', $name), 404); + } + return Application::getInstance()->resolve($name); } protected function instantiated($callback, $request = null) @@ -212,7 +220,17 @@ public function renderRoute(Request $request) if (method_exists($class, $method) === false) { - throw new NotFoundHttpException(sprintf('Method "%s" does not exist in class "%s"', $method, $className), 404); + $exception = NotFoundHttpException::class; + if (env('DEBUG_MODE_SETTINGS', '{"controller_missing": true, "method_missing": true}') != null) { + $debugSettings = json_decode(env('DEBUG_MODE_SETTINGS', '{"controller_missing": true, "method_missing": true}'), true); + + if (isset($debugSettings['method_missing'])) { + if ($debugSettings['method_missing'] === true) { + $exception = NotFoundHttpMethodException::class; + } + } + } + throw new $exception(sprintf('Method "%s" does not exist in class "%s"', $method, $className), 404); } $parameters = $this->getParameters(); diff --git a/src/Yuga/Scaffold/Scaffold.php b/src/Yuga/Scaffold/Scaffold.php index 126d1a8..f291fd1 100644 --- a/src/Yuga/Scaffold/Scaffold.php +++ b/src/Yuga/Scaffold/Scaffold.php @@ -51,6 +51,7 @@ class Scaffold extends Types self::TYPE_MULTILINESTRING => 'string', self::TYPE_MULTIPOLYGON => 'string', self::TYPE_GEOMETRYCOLLECTION => 'string', + self::TYPE_EDITOR => 'longtext', ]; public static function getMethod($type) diff --git a/src/Yuga/Scaffold/Types.php b/src/Yuga/Scaffold/Types.php index c850720..7cd99ae 100644 --- a/src/Yuga/Scaffold/Types.php +++ b/src/Yuga/Scaffold/Types.php @@ -50,6 +50,7 @@ class Types const TYPE_HIDDEN = 'HIDDEN'; const TYPE_FILE = 'FILE'; const TYPE_RANGE = 'RANGE'; + const TYPE_EDITOR = 'EDITOR'; public static $INPUT_TYPES = [ self::TYPE_EMAIL => 'email', @@ -98,5 +99,6 @@ class Types self::TYPE_MULTILINESTRING => 'text', self::TYPE_MULTIPOLYGON => 'text', self::TYPE_GEOMETRYCOLLECTION => 'text', + self::TYPE_EDITOR => 'editor', ]; } \ No newline at end of file diff --git a/src/Yuga/Session/Session.php b/src/Yuga/Session/Session.php index 599ebc1..8a06595 100755 --- a/src/Yuga/Session/Session.php +++ b/src/Yuga/Session/Session.php @@ -86,6 +86,11 @@ public static function exists($name) return (isset($_SESSION[$name])) ? true : false; } + public static function has($name) + { + return self::exists($name); + } + public static function delete($name) { if (self::exists($name)) { diff --git a/src/Yuga/Views/Widgets/Html/Html.php b/src/Yuga/Views/Widgets/Html/Html.php index 4bb3f2e..fc8a98b 100755 --- a/src/Yuga/Views/Widgets/Html/Html.php +++ b/src/Yuga/Views/Widgets/Html/Html.php @@ -1,4 +1,5 @@ tag = $tag; $this->closingType = static::CLOSE_TYPE_TAG; + + if (!static::$instance) { + static::$instance = $this; + } + } + + /** + * Return a static instance of the Element + * + * @param null + * + * @return static + */ + public static function getInstance() + { + return static::$instance; } /** @@ -76,6 +96,13 @@ public function addAttribute($name, $value = '') return $this; } + public function addParentAttribute($name, $value = '') + { + $this->parent->addAttribute($name, $value); + + return $this; + } + /** * @param array $attributes * @return static $this @@ -89,6 +116,34 @@ public function setAttributes(array $attributes) return $this; } + /** + * @param array $attributes + * @return static $this + */ + public function addAttributes(array $attributes) + { + return $this->setAttributes($attributes); + } + + /** + * @param array $attributes + * @return static $this + */ + public function setParentAttributes(array $attributes) + { + $this->parent->setAttributes($attributes); + return $this; + } + + /** + * @param array $attributes + * @return static $this + */ + public function addParentAttributes(array $attributes) + { + return $this->setParentAttributes($attributes); + } + public function attr($name, $value = '', $replace = true) { if ($replace === true) { @@ -153,6 +208,12 @@ protected function render() $html = $after; $output .= ($html instanceof static) ? $html->render() : $html; } + + $parent = $this->getParent(); + + if ($parent) { + $output = $parent->addInnerHtml($output)->render(); + } return $output; } @@ -174,6 +235,18 @@ public function addClass($class) return $this; } + /** + * Add class + * @param string $class + * @return static + */ + public function addParentClass($class) + { + foreach (explode(" ", $class) as $cls) + $this->parent->addAttribute('class', $cls); + return $this; + } + /** * @return string $closingType */ @@ -277,4 +350,43 @@ public function findItemByAttribute($element, $name, $value, $strict = false) return null; } + + /** + * Set parent html + * + * @param Html|string|null $parent + * @param array $attributes + * @return static + */ + public function setParent($parent = null, array $attributes = []) + { + if ($parent) { + if ($parent instanceof static) { + $this->parent = $parent->setAttributes($attributes); + } else { + $this->parent = (new self($parent))->setAttributes($attributes); + } + } + + + return $this; + } + + /** + * Get parent html + * @return Html|null + */ + public function getParent() + { + return $this->parent; + } + + /** + * Add a parent to an html Element + */ + public function addParent($element) + { + $this->setParent($element); + return $this->parent; + } } \ No newline at end of file diff --git a/src/Yuga/Views/Widgets/Html/HtmlButton.php b/src/Yuga/Views/Widgets/Html/HtmlButton.php index 772fdca..91464c5 100644 --- a/src/Yuga/Views/Widgets/Html/HtmlButton.php +++ b/src/Yuga/Views/Widgets/Html/HtmlButton.php @@ -58,12 +58,23 @@ public function addInputAttribute($name) */ public function isClicked() { - $value = $this->getValue(); + $value = $this->getValue(); + + // echo '
';
+        // print_r($this->getParent());
+        // die();
 		return $value !== null && $value !== [];
     }
     
     public function getValue()
     {
-        return count($value = $this->getAttribute('value')) > 0 ? $value[0] : null;
+        $value = $this->getAttribute('value');
+        return  $value ? $value[0] : null;
+    }
+
+    public function getName()
+    {
+        $name = $this->getAttribute('name');
+        return  $name ? $name[0] : null;
     }
 }
\ No newline at end of file
diff --git a/src/Yuga/Views/Widgets/Html/HtmlForm.php b/src/Yuga/Views/Widgets/Html/HtmlForm.php
index 8672d8b..777a652 100755
--- a/src/Yuga/Views/Widgets/Html/HtmlForm.php
+++ b/src/Yuga/Views/Widgets/Html/HtmlForm.php
@@ -88,6 +88,14 @@ public function input($name, $type = 'text', $value = null, $saveValue = true)
         return (new HtmlInput($type, $name, $value))->id($name);
     }
 
+    /**
+     * Add a submit button
+     * 
+     * @param string $name
+     * @param string $type
+     * @param string|null $value
+     * @param bool $saveValue
+     */
     public function submitButton($name, $type = 'submit', $value = null, $saveValue = true)
     {
         if ($saveValue && ($value === null && input()->get($name) !== null || request()->getMethod() !== 'get')) {
@@ -144,8 +152,12 @@ public function __toString(): string
                 $this->fireFormEvents($this);
             }
             if ($this->make === true) {
-                $this->buildForm();
-            }
+                // $this->buildOutput();
+                $this->buildFormWithTable();
+            } 
+            // else {
+            //     $this->buildOutput('div');
+            // }
             return parent::__toString();
         } catch (\Throwable $e) {
             trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}: {$e->getLine()}", E_USER_ERROR);
@@ -256,7 +268,24 @@ public function addSelect($name, $label, $data = null, $value = null)
         return $control;
     }
 
-    protected function buildForm()
+    public function buildOutput($formParent = 'table')
+    {
+        if ($formParent == 'table')
+            return $this->buildFormWithTable();
+        else
+            return $this->buildFormWithParent($formParent);
+    }
+
+    protected function buildFormWithParent(?string $formParent = null)
+    {
+        foreach ($this->controls as $name => $controlObject) {
+            $this->append($controlObject['control']);
+        }
+
+        return $this;
+    }
+
+    protected function buildFormWithTable()
     {
         $layout = '';
         
diff --git a/src/Yuga/Views/Widgets/Html/HtmlInput.php b/src/Yuga/Views/Widgets/Html/HtmlInput.php
index d1b8fbe..8f40178 100755
--- a/src/Yuga/Views/Widgets/Html/HtmlInput.php
+++ b/src/Yuga/Views/Widgets/Html/HtmlInput.php
@@ -64,7 +64,7 @@ public function isRequired()
 
     public function multiple()
     {
-        return $this->addInputAttribute('required');
+        return $this->addInputAttribute('multiple');
     }
 
     public function maxLength($maxLength)
diff --git a/src/Yuga/Views/Widgets/Xml/XmlElement.php b/src/Yuga/Views/Widgets/Xml/XmlElement.php
index 87aafec..e991b8d 100755
--- a/src/Yuga/Views/Widgets/Xml/XmlElement.php
+++ b/src/Yuga/Views/Widgets/Xml/XmlElement.php
@@ -61,6 +61,7 @@ public function getParent()
     public function setParent($parent)
     {
         $this->parent = $parent;
+        return $this;
     }
 
     public function addChild(IXmlNode $node)