diff --git a/apps/Admin/Controllers/Abstract/AdminSingleController.php b/apps/Admin/Controllers/Abstract/AdminSingleController.php index 04c08e3..5b4c9a2 100644 --- a/apps/Admin/Controllers/Abstract/AdminSingleController.php +++ b/apps/Admin/Controllers/Abstract/AdminSingleController.php @@ -38,6 +38,7 @@ abstract class AdminSingleController extends AdminBaseController protected $field_title = 'field_id'; protected $edit_title_template = 'Edit [:verbose] "[:field]"'; protected $can_save = true; + protected $is_new = false; /** * Function names with $object attribute. @@ -53,6 +54,7 @@ abstract class AdminSingleController extends AdminBaseController */ public function __construct($is_new = false) { + $this->is_new = $is_new; $this->context['is_new'] = $is_new; } diff --git a/apps/Admin/Controllers/AdminCategoryController.php b/apps/Admin/Controllers/AdminCategoryController.php new file mode 100644 index 0000000..a2638cd --- /dev/null +++ b/apps/Admin/Controllers/AdminCategoryController.php @@ -0,0 +1,21 @@ + 'name', + 'input_type' => 'text', + 'input_attrs' => ['required'] + ] + ); +} \ No newline at end of file diff --git a/apps/Admin/Controllers/AdminCategoryListController.php b/apps/Admin/Controllers/AdminCategoryListController.php new file mode 100644 index 0000000..aa824f2 --- /dev/null +++ b/apps/Admin/Controllers/AdminCategoryListController.php @@ -0,0 +1,17 @@ + 'field_name' + ); + protected $single_router_name = 'admin:category'; + protected $create_router_name = 'admin:category-new'; + protected $verbose_name = "category"; + protected $verbose_name_multiply = "categories"; +} \ No newline at end of file diff --git a/apps/Admin/Controllers/AdminDeleteController.php b/apps/Admin/Controllers/AdminDeleteController.php index ed9e085..17ac960 100644 --- a/apps/Admin/Controllers/AdminDeleteController.php +++ b/apps/Admin/Controllers/AdminDeleteController.php @@ -9,6 +9,49 @@ use Lycoreco\Apps\Users\Models\UserModel; */ class AdminDeleteController extends Abstract\AdminBaseController { + const DELETE_MODELS = [ + [ + 'url_name' => 'users', + 'model' => 'Lycoreco\Apps\Users\Models\UserModel', + 'field_display' => 'field_username', + 'back_to' => 'admin:user', + 'success_to' => 'admin:user-list' + ], + [ + 'url_name' => 'user-banlist', + 'model' => 'Lycoreco\Apps\Users\Models\BanlistModel', + 'field_display' => 'field_reason', + 'back_to' => 'admin:ban' + ], + [ + 'url_name' => 'recipes', + 'model' => 'Lycoreco\Apps\Recipes\Models\RecipeModel', + 'field_display' => 'field_title', + 'back_to' => 'admin:recipe', + 'success_to' => 'admin:recipe-list' + ], + [ + 'url_name' => 'ingredients', + 'model' => 'Lycoreco\Apps\Recipes\Models\IngredientModel', + 'field_display' => 'field_name', + 'back_to' => 'admin:ingredient', + 'success_to' => 'admin:ingredient-list' + ], + [ + 'url_name' => 'categories', + 'model' => 'Lycoreco\Apps\Recipes\Models\CategoryModel', + 'field_display' => 'field_name', + 'back_to' => 'admin:category', + 'success_to' => 'admin:category-list' + ], + [ + 'url_name' => 'recipe-ingredients', + 'model' => 'Lycoreco\Apps\Recipes\Models\IngredientInRecipeModel', + 'field_display' => 'ingredient_name', + 'back_to' => 'admin:ing-cat-rel', + ], + ]; + protected $template_name = APPS_PATH . '/Admin/Templates/delete.php'; /** @@ -22,17 +65,15 @@ class AdminDeleteController extends Abstract\AdminBaseController $id = $this->url_context['url_2']; $model_class = ''; - switch ($this->url_context['url_1']) { - case 'users': - $model_class = "Lycoreco\Apps\Users\Models\UserModel"; + foreach (self::DELETE_MODELS as $delete_model) { + if($this->url_context['url_1'] == $delete_model['url_name']) { + $model_class = $delete_model['model']; break; - case 'user-banlist': - $model_class = "Lycoreco\Apps\Users\Models\BanlistModel"; - break; - - default: - return null; + } } + if(empty($model_class)) + return null; + return $model_class::get(array( [ 'name' => 'obj.id', @@ -52,16 +93,12 @@ class AdminDeleteController extends Abstract\AdminBaseController // Display field to show what's model $field = ''; $back_url = ''; - switch ($this->url_context['url_1']) { - case 'users': - $back_url = get_permalink('admin:user', [$model->get_id()]); - $field = 'field_username'; - break; - case 'user-banlist': - $back_url = get_permalink('admin:ban', [$model->get_id()]); - $field = 'field_reason'; - break; + foreach (self::DELETE_MODELS as $delete_model) { + if($this->url_context['url_1'] == $delete_model['url_name']) { + $back_url = get_permalink($delete_model['back_to'], [$model->get_id()]); + $field = $delete_model['field_display']; + } } $context['back_url'] = $back_url; @@ -80,14 +117,14 @@ class AdminDeleteController extends Abstract\AdminBaseController $model->delete(); // Redirect after delete - $type_model = $this->url_context['url_1']; - switch ($type_model) { - case 'users': - $link = get_permalink('admin:user-list'); - break; - default: - $link = get_permalink('admin:home'); + $link = get_permalink('admin:home'); + foreach (self::DELETE_MODELS as $delete_model) { + if($this->url_context['url_1'] == $delete_model['url_name']) { + if(isset($delete_model['success_to'])) { + $link = get_permalink($delete_model['success_to']); + } break; + } } redirect_to($link); } diff --git a/apps/Admin/Controllers/AdminRecipeController.php b/apps/Admin/Controllers/AdminRecipeController.php new file mode 100644 index 0000000..b9c88c6 --- /dev/null +++ b/apps/Admin/Controllers/AdminRecipeController.php @@ -0,0 +1,78 @@ + 'title', + 'input_type' => 'text', + 'input_attrs' => ['required'] + ], + [ + 'model_field' => 'instruction', + 'input_type' => 'textarea', + 'input_attrs' => ['required'] + ], + [ + 'model_field' => 'image_url', + 'input_type' => 'image', + 'input_label' => 'Image', + ], + [ + 'model_field' => 'estimated_time', + 'input_type' => 'number', + 'input_attrs' => ['required'], + 'input_label' => 'Estimated time (min)' + ], + [ + 'model_field' => 'estimated_price', + 'input_type' => 'number', + 'input_attrs' => ['required'], + 'input_label' => 'Estimated price ($)' + ], + [ + 'model_field' => 'status', + 'input_type' => 'select', + 'input_attrs' => ['required'], + 'input_values' => RecipeModel::STATUS + ], + [ + 'model_field' => 'created_at', + 'input_type' => 'text', + 'dynamic_save' => false, + 'input_label' => 'Created at', + 'input_attrs' => ['disabled'] + ] + ); + protected function before_save(&$object) + { + if($this->is_new) + { + $object->field_author_id = CURRENT_USER->get_id(); + } + } + + public function __construct($is_new = false) { + parent::__construct($is_new); + $this->fields[] = [ + 'model_field' => 'category_id', + 'input_type' => 'select', + 'input_label' => 'Categories', + 'input_attrs' => ['required'], + 'input_values' => CategoryModel::get_cat_values() + ]; + } +} \ No newline at end of file diff --git a/apps/Admin/Controllers/AdminRecipeListController.php b/apps/Admin/Controllers/AdminRecipeListController.php new file mode 100644 index 0000000..cdcd88e --- /dev/null +++ b/apps/Admin/Controllers/AdminRecipeListController.php @@ -0,0 +1,20 @@ + 'field_title', + 'Price' => 'get_price()', + 'Status ' => 'get_status()', + 'Creaated at' => 'field_created_at', + ); + protected $single_router_name = 'admin:recipe'; + protected $create_router_name = 'admin:recipe-new'; + protected $verbose_name = "recipe"; + protected $verbose_name_multiply = "recipes"; +} \ No newline at end of file diff --git a/apps/Admin/Controllers/IngredientController.php b/apps/Admin/Controllers/IngredientController.php new file mode 100644 index 0000000..07681eb --- /dev/null +++ b/apps/Admin/Controllers/IngredientController.php @@ -0,0 +1,27 @@ + 'name', + 'input_type' => 'text', + 'input_attrs' => ['required'] + ], + [ + 'model_field' => 'unit_name', + 'input_type' => 'text', + 'input_attrs' => ['required'], + 'input_label' => 'Unit name' + ] + ); +} \ No newline at end of file diff --git a/apps/Admin/Controllers/IngredientListController.php b/apps/Admin/Controllers/IngredientListController.php new file mode 100644 index 0000000..f4795d7 --- /dev/null +++ b/apps/Admin/Controllers/IngredientListController.php @@ -0,0 +1,18 @@ + 'field_name', + 'Unit' => 'field_unit_name' + ); + protected $single_router_name = 'admin:ingredient'; + protected $create_router_name = 'admin:ingredient-new'; + protected $verbose_name = "ingredient"; + protected $verbose_name_multiply = "ingredients"; +} \ No newline at end of file diff --git a/apps/Admin/Controllers/IngredientRecipeRelController.php b/apps/Admin/Controllers/IngredientRecipeRelController.php new file mode 100644 index 0000000..4b7afe7 --- /dev/null +++ b/apps/Admin/Controllers/IngredientRecipeRelController.php @@ -0,0 +1,50 @@ + 'recipe_id', + 'input_type' => 'number', + 'dynamic_save' => false, + 'input_label' => 'Recipe id', + 'input_attrs' => ['required', 'disabled'] + ], + [ + 'model_field' => 'amount', + 'input_type' => 'text', + 'input_attrs' => ['required'] + ], + ); + protected function get_model() + { + $model = parent::get_model(); + + if($this->context['is_new']) + $model->field_recipe_id = (int)$this->url_context['url_1']; + + return $model; + } + public function __construct($is_new = false) { + parent::__construct($is_new); + + $this->fields[] = [ + 'model_field' => 'ingredient_id', + 'input_type' => 'select', + 'input_label' => 'Ingedient', + 'input_attrs' => ['required'], + 'input_values' => IngredientModel::get_ing_values() + ]; + } +} \ No newline at end of file diff --git a/apps/Admin/Controllers/IngredientRecipeRelListController.php b/apps/Admin/Controllers/IngredientRecipeRelListController.php new file mode 100644 index 0000000..1f319e3 --- /dev/null +++ b/apps/Admin/Controllers/IngredientRecipeRelListController.php @@ -0,0 +1,28 @@ + 'ingredient_name', + 'Amount' => 'get_count()' + ); + protected $single_router_name = 'admin:ing-cat-rel'; + protected $verbose_name = "ingredients in recipe"; + protected $verbose_name_multiply = "ingredients in recipe"; + + public function custom_filter_fields() + { + $recipe_id = $this->url_context['url_1']; + return array( + [ + 'name' => 'obj.recipe_id', + 'type' => '=', + 'value' => $recipe_id + ] + ); + } +} diff --git a/apps/Admin/Templates/components/admin-header.php b/apps/Admin/Templates/components/admin-header.php index d5b508a..71bb505 100644 --- a/apps/Admin/Templates/components/admin-header.php +++ b/apps/Admin/Templates/components/admin-header.php @@ -1,5 +1,33 @@ 'Dashboard', + 'icon' => 'fa-solid fa-house', + 'router_name' => 'admin:home', + ], + [ + 'name' => 'Users', + 'icon' => 'fa-solid fa-users', + 'router_name' => 'admin:user-list', + ], + [ + 'name' => 'Recipes', + 'icon' => 'fa-solid fa-bowl-food', + 'router_name' => 'admin:recipe-list' + ], + [ + 'name' => 'Categories', + 'icon' => 'fa-solid fa-tag', + 'router_name' => 'admin:category-list' + ], + [ + 'name' => 'Ingredients', + 'icon' => 'fa-solid fa-carrot', + 'router_name' => 'admin:ingredient-list' + ] +]; ?> @@ -45,19 +73,16 @@ use Lycoreco\Includes\Routing\Router;
diff --git a/apps/Admin/Templates/widgets/ingredients_in_recipe.php b/apps/Admin/Templates/widgets/ingredients_in_recipe.php new file mode 100644 index 0000000..69eebf2 --- /dev/null +++ b/apps/Admin/Templates/widgets/ingredients_in_recipe.php @@ -0,0 +1,22 @@ +
+
Ingredients
+
+
+ + +
+ + +
get_count() ?>
+
+ + +
No ingredients
+ +
+ +
+
\ No newline at end of file diff --git a/apps/Admin/Templates/widgets/ingredients_in_recipe_relation.php b/apps/Admin/Templates/widgets/ingredients_in_recipe_relation.php new file mode 100644 index 0000000..edda2a6 --- /dev/null +++ b/apps/Admin/Templates/widgets/ingredients_in_recipe_relation.php @@ -0,0 +1,10 @@ +
+
Model relations
+
+
Ingredient:
+
field_name ?>
+ +
Recipe:
+
field_title ?>
+
+
\ No newline at end of file diff --git a/apps/Admin/Templates/widgets/recipe_author.php b/apps/Admin/Templates/widgets/recipe_author.php new file mode 100644 index 0000000..1e02c74 --- /dev/null +++ b/apps/Admin/Templates/widgets/recipe_author.php @@ -0,0 +1,6 @@ +
+
Author
+ +
\ No newline at end of file diff --git a/apps/Admin/components.php b/apps/Admin/components.php index eb1c6e8..c001c84 100644 --- a/apps/Admin/components.php +++ b/apps/Admin/components.php @@ -4,6 +4,11 @@ use Lycoreco\Apps\Users\Models\{ UserModel, BanlistModel }; +use Lycoreco\Apps\Recipes\Models\{ + RecipeModel, + IngredientModel, + IngredientInRecipeModel +}; function the_admin_header(string $title) { @@ -30,4 +35,49 @@ function the_user_banlist(UserModel $user) ['-obj.end_at']); require APPS_PATH . '/Admin/Templates/widgets/user_banlist.php'; +} + +function the_recipe_author(RecipeModel $recipe) +{ + $author = UserModel::get(array( + [ + 'name' => 'obj.id', + 'type' => '=', + 'value' => $recipe->field_author_id + ] + )); + + require APPS_PATH . '/Admin/Templates/widgets/recipe_author.php'; +} + +function the_recipe_ingredients(RecipeModel $recipe) +{ + $ingredients = IngredientInRecipeModel::filter(array( + [ + 'name' => 'obj.recipe_id', + 'type' => '=', + 'value' => $recipe->get_id() + ] + )); + + require APPS_PATH . '/Admin/Templates/widgets/ingredients_in_recipe.php'; +} +function the_recipe_ingredients_relation(IngredientInRecipeModel $relation) +{ + $ingredient = IngredientModel::get(array( + [ + 'name' => 'obj.id', + 'type' => '=', + 'value' => $relation->field_ingredient_id + ] + )); + $recipe = RecipeModel::get(array( + [ + 'name' => 'obj.id', + 'type' => '=', + 'value' => $relation->field_recipe_id + ] + )); + + require APPS_PATH . '/Admin/Templates/widgets/ingredients_in_recipe_relation.php'; } \ No newline at end of file diff --git a/apps/Admin/urls.php b/apps/Admin/urls.php index e40d49d..22e813f 100644 --- a/apps/Admin/urls.php +++ b/apps/Admin/urls.php @@ -9,6 +9,9 @@ $admin_urls = [ // Lists new Path('/admin/users', new Controllers\AdminUserListController(), 'user-list'), + new Path('/admin/recipes',new Controllers\AdminRecipeListController(), 'recipe-list'), + new Path('/admin/categories',new Controllers\AdminCategoryListController(), 'category-list'), + new Path('/admin/ingredients',new Controllers\IngredientListController(), 'ingredient-list'), ////// Single object /////// // User @@ -20,6 +23,23 @@ $admin_urls = [ new Path('/admin/user/[:int]/ban/new', new Controllers\AdminBanController(true), 'ban-new'), new Path('/admin/ban/[:int]', new Controllers\AdminBanController(false), 'ban'), + // Recipe + new Path('/admin/recipe/[:int]', new Controllers\AdminRecipeController(), 'recipe'), + new Path('/admin/recipe/new', new Controllers\AdminRecipeController(true), 'recipe-new'), + + // Category + new Path('/admin/category/[:int]', new Controllers\AdminCategoryController(), 'category'), + new Path('/admin/category/new', new Controllers\AdminCategoryController(true), 'category-new'), + + // Ingredient + new Path('/admin/ingredient/[:int]', new Controllers\IngredientController(), 'ingredient'), + new Path('/admin/ingredient/new', new Controllers\IngredientController(true), 'ingredient-new'), + + // Recipe ingedient relation + new Path('/admin/recipe/[:int]/ingredients', new Controllers\IngredientRecipeRelListController(), 'ing-cat-rel-list'), + new Path('/admin/recipe/ingredient/[:int]', new Controllers\IngredientRecipeRelController(), 'ing-cat-rel'), + new Path('/admin/recipe/[:int]/ingredient/new', new Controllers\IngredientRecipeRelController(true), 'ing-cat-rel-new'), + // Dynamic delete for every object type new Path('/admin/[:string]/[:int]/delete', new Controllers\AdminDeleteController(), 'delete') ]; diff --git a/apps/Recipes/Models/CategoryModel.php b/apps/Recipes/Models/CategoryModel.php index e2d863d..3ed441f 100644 --- a/apps/Recipes/Models/CategoryModel.php +++ b/apps/Recipes/Models/CategoryModel.php @@ -7,6 +7,7 @@ class CategoryModel extends BaseModel { public $field_name; + static protected $search_fields = ['obj.name']; static protected $table_name = 'categories'; static protected $table_fields = [ 'id' => 'int', @@ -21,4 +22,14 @@ class CategoryModel extends BaseModel );'); return $result; } + + public static function get_cat_values() + { + $cat_list = self::filter(array()); + $result = array(); + foreach($cat_list as $cat) { + $result[] = [ $cat->get_id(), $cat->field_name ]; + } + return $result; + } } \ No newline at end of file diff --git a/apps/Recipes/Models/IngredientInRecipeModel.php b/apps/Recipes/Models/IngredientInRecipeModel.php index 1082ad9..702b9e1 100644 --- a/apps/Recipes/Models/IngredientInRecipeModel.php +++ b/apps/Recipes/Models/IngredientInRecipeModel.php @@ -6,14 +6,27 @@ use Lycoreco\Includes\Model\BaseModel; class IngredientInRecipeModel extends BaseModel { public $field_ingredient_id; - public $field_receipt_id; + public $field_recipe_id; public $field_amount; + + static protected $search_fields = ['tb1.name']; + public $ingredient_name; + public $ingredient_unit; + static protected $additional_fields = array( + [ + 'field' => [ + 'tb1.name AS ingredient_name', + 'tb1.unit_name AS ingredient_unit' + ], + 'join_table' => 'ingredients tb1 ON tb1.id = obj.ingredient_id' + ] + ); static protected $table_name = 'recipe_ingredients'; static protected $table_fields = [ 'id' => 'int', 'ingredient_id' => 'int', - 'receipt_id' => 'int', + 'recipe_id' => 'int', 'amount' => 'int' ]; public static function init_table() @@ -22,12 +35,16 @@ class IngredientInRecipeModel extends BaseModel id INT AUTO_INCREMENT PRIMARY KEY, ingredient_id INT NOT NULL, - receipt_id INT NOT NULL, + recipe_id INT NOT NULL, amount INT NOT NULL, FOREIGN KEY (ingredient_id) REFERENCES ingredients(id) ON DELETE CASCADE, - FOREIGN KEY (receipt_id) REFERENCES recipes(id) ON DELETE CASCADE + FOREIGN KEY (recipe_id) REFERENCES recipes(id) ON DELETE CASCADE );'); return $result; } + public function get_count() + { + return $this->field_amount . ' ' . $this->ingredient_unit; + } } \ No newline at end of file diff --git a/apps/Recipes/Models/IngredientModel.php b/apps/Recipes/Models/IngredientModel.php index 550c3c5..8990a69 100644 --- a/apps/Recipes/Models/IngredientModel.php +++ b/apps/Recipes/Models/IngredientModel.php @@ -7,6 +7,8 @@ class IngredientModel extends BaseModel { public $field_name; public $field_unit_name; + + static protected $search_fields = ['obj.name']; static protected $table_name = 'ingredients'; static protected $table_fields = [ @@ -24,4 +26,13 @@ class IngredientModel extends BaseModel );'); return $result; } + public static function get_ing_values() + { + $ing_list = self::filter(array()); + $result = array(); + foreach($ing_list as $ing) { + $result[] = [ $ing->get_id(), $ing->field_name . ' ('. $ing->field_unit_name .')' ]; + } + return $result; + } } \ No newline at end of file diff --git a/apps/Recipes/Models/RecipeModel.php b/apps/Recipes/Models/RecipeModel.php index 13628ea..67ea052 100644 --- a/apps/Recipes/Models/RecipeModel.php +++ b/apps/Recipes/Models/RecipeModel.php @@ -7,20 +7,26 @@ class RecipeModel extends BaseModel { public $field_title; public $field_instruction; + public $field_image_url; public $field_estimated_time; public $field_estimated_price; public $field_category_id; public $field_author_id; public $field_status; public $field_created_at; + + const STATUS = [[ 'publish', 'Publish' ], [ 'pending', 'Pending' ]]; + static protected $search_fields = ['obj.title']; static protected $table_name = 'recipes'; static protected $table_fields = [ 'id' => 'int', 'title' => 'string', 'instruction' => 'string', + 'image_url' => 'string', 'estimated_time' => 'int', - 'estimated_price' => 'int', + 'estimated_price' => 'float', + 'category_id' => 'int', 'author_id' => 'int', 'status' => 'string', 'created_at' => 'DateTime' @@ -32,14 +38,31 @@ class RecipeModel extends BaseModel title VARCHAR(255) NOT NULL, instruction TEXT NOT NULL, + image_url VARCHAR(255) NULL, estimated_time INT NOT NULL, estimated_price INT NOT NULL, + category_id INT NOT NULL, author_id INT NOT NULL, status VARCHAR(20) NOT NULL CHECK (status IN (\'publish\', \'pending\')), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE + FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE );'); return $result; } + public function get_price() + { + return $this->field_estimated_price . '$'; + } + public function get_status() + { + return ucfirst($this->field_status); + } + public function get_image_url() { + if($this->field_image_url) + return MEDIA_URL . $this->field_image_url; + + return null; + } } \ No newline at end of file diff --git "a/media/Lycoreco\\Apps\\Recipes\\Models\\RecipeModel/chana-masala-recipe_684f4743a2a80.jpg" "b/media/Lycoreco\\Apps\\Recipes\\Models\\RecipeModel/chana-masala-recipe_684f4743a2a80.jpg" new file mode 100644 index 0000000..63d9ff9 Binary files /dev/null and "b/media/Lycoreco\\Apps\\Recipes\\Models\\RecipeModel/chana-masala-recipe_684f4743a2a80.jpg" differ diff --git "a/media/Lycoreco\\Apps\\Recipes\\Models\\RecipeModel/images_684f027f3a8da.jpeg" "b/media/Lycoreco\\Apps\\Recipes\\Models\\RecipeModel/images_684f027f3a8da.jpeg" new file mode 100644 index 0000000..d74d844 Binary files /dev/null and "b/media/Lycoreco\\Apps\\Recipes\\Models\\RecipeModel/images_684f027f3a8da.jpeg" differ