This commit is contained in:
Torsten 2024-12-22 14:02:54 +01:00
parent 1e22d28754
commit 6b926d3afe
126 changed files with 128562 additions and 104297 deletions

View file

@ -0,0 +1,62 @@
Inside Devilbox container:
```bash
devilbox@php-8.1.14 in /shared/httpd $ pwd
/shared/httpd
mkdir myproject
cd myproject
composer create-project codeigniter4/appstarter myprojectapp
ln -s myprojectapp/public htdocs
```
Setup db settings in .env:
```txt
CI_ENVIRONMENT = development
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
app.baseURL = 'http://godotweb.local'
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
database.default.hostname = godotweb.local
database.default.database = godotweb
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
```
Add shield:
```bash
composer require codeigniter4/shield
```
In case of issues, see installation.
```bash
composer config minimum-stability dev
composer config prefer-stable true
```
```bash
php spark shield:setup
```
####
SET DEFAULT LOCALE
Config/App.php
```php
public bool $negotiateLocale = true;
public string $defaultLocale = 'en';
public array $supportedLocales = ['en', 'de'];
```

View file

@ -0,0 +1,146 @@
```bash
php spark make:controller Api/Auth --suffix --restful
```
Routes.php
```php
//Get
$routes->get("logout", "AuthController::logout", ["filter" => "apiauth"]);
```
Api/AuthController.php
```php
<?php
namespace App\Controllers\Api;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\RESTful\ResourceController;
use CodeIgniter\Shield\Models\UserModel;
use CodeIgniter\Shield\Entities\User;
class AuthController extends ResourceController
{
//Post
public function register()
{
$rules = [
"username" => "required|is_unique[users.username]",
"email" => "required|valid_email|is_unique[auth_identities.secret]", // gets written to secret field in user table
"password" => "required" // gets written to secret 2 field in user table
];
if (!$this->validate($rules))
{
return $this->respondCreated([
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
]);
}
$um = new UserModel(); // coming from Shield
$userEntity = new User([
"username" => $this->request->getVar("username"),
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
]);
$um->save($userEntity);
return $this->respondCreated( [
"status" => true,
"message" => "User saved successfully",
"data" => []
]);
}
//////////////////////////////////////
// Post
public function login()
{
if(auth()->loggedIn()) {
auth()->logout();
}
$rules = [
"email" => "required|valid_email",
"password" => "required"
];
if (!$this->validate($rules)) {
return $this->respondCreated([
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
]);
}
// success
$credentials = [
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
];
$loginAttempt = auth()->attempt($credentials);
if (!$loginAttempt->isOK()) {
return $this->respondCreated([
"status" => false,
"message" => "Invalid login details",
"data" => []
]);
}
// We have a valid data set
$um = new UserModel();
$userData = $um->findById(auth()->id());
$token = $userData->generateAccessToken("thisismysecretkey");
$auth_token = $token->raw_token; // Only available after generation
return $this->respondCreated( [
"status" => true,
"message" => "User logged in successfully",
"data" => [
"token" => $auth_token
]
]);
}
////////////////////////
public function logout()
{
auth()->logout();
auth()->user()->revokeAllAccessTokens();
return $this->respondCreated([
"status" => true,
"message" => "User logged out successfully",
"data" => []
]);
}
//Get
public function profile()
{
$userId = auth()->id();
return $this->respondCreated([
"status" => true,
"message" => "Profile api called",
"data" => []
]);
}
public function accessDenied()
{
return $this->respondCreated([
"status" => false,
"message" => "Invalid access",
"data" => []
]);
}
}
```

View file

@ -0,0 +1,22 @@
https://www.youtube.com/watch?v=_ZRHt-fWJpc&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=29
app/Config/Routes.php
Remember: Shield added =>
```php
service('auth')->routes($routes)
```
```php
// API routes (put below service('auth'))
$routes->group("api", ["namespace" => "App\Controller\Api"], function($routes) {
$routes->post("register", "AuthController::register");
$routes->post("login", "AuthController::login");
$routes->get("profile", "AuthController::profile");
$routes->get("logout", "AuthController::logout", ["filter"=>"apiauth"]);
//$routes->post("add-project", "ProjectController::addProject");
//$routes->get("list-projects", "ProjectController::listProjects");
//$routes->delete("delete-project/(:num)", "ProjectController::deleteProject/$1");
});
```

View file

@ -0,0 +1,46 @@
https://www.youtube.com/watch?v=USqOc-GCA4s&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=32
Create AuthFilter.php
```bash
php spark make:filter Auth --suffix
```
Define before method in AuthFilter.php
```php
public function before(RequestInterface $request, $arguments = null)
{
helper("auth");
if (!auth("tokens")->loggedIn()) {
return redirect()->to(base_url("api/ invalid-access")); // need to create invalid-access route
}
}
```
Routes.php
```php
// API ROUTES
$routes->group("api",["namespace]=> "App\Controllers\Api"], function($routes) {
...
$routes->get("invalid-access", "AuthController::accessDenied");
§routes->get('demo-method", "AuthController::demoMethod",["filter" => "apiauth"]); // Filter Name is defined in aliases array in Filters.php below.
...
```
Add filter to app/Config/Filters.php
```php
use App\Filters\AuthFilter;
public array $aliases = [
'csrf' => CSRF::class,
'toolbar' => DebugToolbar::class,
'honeypot' => Honeypot::class,
'invalidchars' => InvalidChars::class,
'secureheaders' => SecureHeaders::class,
'apiauth' => AuthFilter::class
]
```
Authorize request by adding field "Authorization" with value "Bearer xxxxxx" in Request Header:
![[Pasted image 20241127140801.png]]

View file

@ -0,0 +1,5 @@
![[Pasted image 20241214094809.png]]
![[Pasted image 20241214094906.png]]
600933326ac42a7f1669bfcaceb4bf1f973c8f64f54dccff9d6c424a9c2c0e5d

View file

@ -0,0 +1,41 @@
```bash
php spark make:model Board --suffix
php spark make:controller Api/Board --suffix --restful
```
Add allowed fields to model:
(BoardModel.php)
```php
$allowedFields = ["name"];
```
```php
php spark make:migration create_boards
```
Migration file:
```php
//up:
$this->forge->addField([
"id" => [ "type"=>"INT", "constraint"=>5, "auto increment" => true, "unsigned" => true ],
"name" => [ "type"=>"VARCHAR", "constraint" => 120, "null" => false ]
]);
$this->forge->addPrimaryKey("id);
$this->forge->createTable("boards");
//down:
$this->forge->dropTable("boards");
```
```bash
php spark migrate:status
php spark migrate
```
Create seeder ?

View file

@ -0,0 +1,40 @@
Inside Devilbox container:
```bash
devilbox@php-8.1.14 in /shared/httpd $ pwd
/shared/httpd
mkdir myproject
cd myproject
composer create-project codeigniter4/appstarter myprojectapp
ln -s myprojectapp/public htdocs
```
Add shield:
```bash
composer require codeigniter4/shield
```
In case of issues, see installation.
```bash
composer config minimum-stability dev
composer config prefer-stable true
```
```bash
php spark shield:setup
```
####
SET DEFAULT LOCALE
Config/App.php
```php
public bool $negotiateLocale = true;
public string $defaultLocale = 'en';
public array $supportedLocales = ['en', 'de'];
```

View file

@ -0,0 +1,32 @@
```bash
php spark make:scaffold Product
```
Creates Controller, Model, Migration, Seeder
```php
//up:
$this->forge->addField((["id"=>
["type"=>"INT",
"constraint"=>5,
"auto increment" => true,
"unsigned" => true
],
"name" => ["type"=>"VARCHAR".
"constraint" => 120,
"null" => false
]
]
));
$this->forge->addPrimaryKey("id);
$this->forge->createTable("students");
//down:
$this->forge->dropTable("students");
```
```bash
php spark migrate:status
php spark migrate
```

View file

@ -0,0 +1,27 @@
https://www.youtube.com/watch?v=QaNGT-hj0so&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=8
![[Pasted image 20241112083749.png]]
![[Pasted image 20241112084116.png]]
Add route to Controller+method in Config/Routes.php:
![[Pasted image 20241112084252.png]]
Example for using where clause ( second parameter in update method ):
![[Pasted image 20241112084920.png]]
Delete:
![[Pasted image 20241112085347.png]]
Select all:
![[Pasted image 20241112090019.png]]
![[Pasted image 20241112090048.png]]
Select with where clause
![[Pasted image 20241112090400.png]]
For single row result, we directly load into Array ( instead of Array of Array)
![[Pasted image 20241112090526.png]]

View file

@ -0,0 +1,36 @@
https://www.youtube.com/watch?v=4_MdtVqfH1o&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=9
```bash
php spark make:model Student --suffix
```
Creates StudentModel.php in app/Models
Add allowedFields
![[Pasted image 20241113082554.png]]
Add Model to Controller
![[Pasted image 20241113082703.png]]
![[Pasted image 20241113083139.png]]
add to routes
```php
$routes->get("add-student", "StudentController::insertStudent");
```
update example (condition, data):
![[Pasted image 20241113083603.png]]
delete:
![[Pasted image 20241113083823.png]]
get all :
![[Pasted image 20241113084056.png]]
get single with generic condition:
![[Pasted image 20241113084645.png]]

View file

@ -0,0 +1,23 @@
For creating dummy data
Seeder files go into app/Database/Seeds
```bash
php spark make:seeder Student --suffix
```
fill run method
![[Pasted image 20241113085432.png]]
Run seeder file
```bash
php spark db:seed StudentSeeder
```
Mass dummy data using Factory / Faker
![[Pasted image 20241113085948.png]]
![[Pasted image 20241113090300.png]]

View file

@ -0,0 +1,33 @@
https://www.youtube.com/watch?v=WGtj1Ihlf10&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=11
get, post, put/patch, delete
![[Pasted image 20241114084652.png]]
![[Pasted image 20241114084843.png]]
![[Pasted image 20241114084916.png]]
![[Pasted image 20241114084945.png]]
Routes.php
![[Pasted image 20241114085118.png]]
Test using postman
![[Pasted image 20241114085726.png]]
![[Pasted image 20241114085814.png]]
![[Pasted image 20241114085826.png]]
Remove debugging noise in payload by switching to production environment in .env
Method spoofing ( changing POST into DELETE request )
![[Pasted image 20241114090303.png]]

View file

@ -0,0 +1,29 @@
https://www.youtube.com/watch?v=4neOZhzn-qI&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=12
![[Pasted image 20241115082725.png]]
app/Config/Routes.php
![[Pasted image 20241115082852.png]]
http://godotweb.local/product/add
http://godotweb.local/product/list
http://godotweb.local/category/add
http://godotweb.local/category/list
**ROUTE NAMESPACE**
Create subfolder in Controllers directory
```bash
php spark make:controller Admin/Admin --suffix
```
![[Pasted image 20241115084552.png]]
```bash
php spark make:controller Seller/Seller --suffix
```
![[Pasted image 20241115084636.png]]
Access Controller in subfolder using namespace parameter in routes group method:
![[Pasted image 20241115085338.png]]

View file

@ -0,0 +1,12 @@
https://www.youtube.com/watch?v=rlIKHZ5Nq2U&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=14
app/Filters
app/Config/Filters.php
![[Pasted image 20241116111944.png]]
```bash
php spark make:filter Auth --suffix
```
![[Pasted image 20241116113439.png]]
![[Pasted image 20241116113532.png]]

View file

@ -0,0 +1,11 @@
```bash
php spark make:controller Api/Api --suffix --restful
```
#17/38
== > Created controller ApiController (in Controlles subfolder Api) will have 9 methods.
( WHich the tutorial doesnt use, basically only difference to standard Controllers is usage of ResourceController)
![[Pasted image 20241117112106.png]]

View file

@ -0,0 +1,8 @@
Routes.php
![[Pasted image 20241117113037.png]]
Route parameter
![[Pasted image 20241117113342.png]]

View file

@ -0,0 +1,51 @@
![[Pasted image 20241117113802.png]]
```php
$studentObject = new StudentModel();
$imageFile = $this->request->getFile("profile_image");
// only go through image storing logic if image actually exists in payload
if (isset($imageFile) && !empty($imageFile)) { // with image
$imageName = $imageFile->getName();
$tempArray = explode(".", $imageName);
$newImageName = round(microtime(true)) . "" . end($tempArray);
if($imageFile->move("images/" . $newImageName)) { // move automatically creates images folder if not exists
$data = [
"name" => $this->request->getVar("name"),
"email" => $this->request->getVar("email"),
"profile_image" => "images/" . $newImageName
];
}
else {
$response = [
"status" => false,
"message" => "Image Upload failed",
"data" => []
];
}
}
else { // without image
$data = [
"name" => $this->request->getVar("name"),
"email" => $this->request->getVar("email"),
];
}
// store student
if ($studentObject->insert($data)) {
$response = [
"status" => true,
"message" => "Student saved successfully",
"data" => []
];
} else {
$response = [
"status" => false,
"message" => "Failed to save student",
"data" => []
];
}
```

View file

@ -0,0 +1,8 @@
![[Pasted image 20241118085649.png]]
**![[Pasted image 20241118090014.png]]
![[Pasted image 20241118090047.png]]

View file

@ -0,0 +1 @@
https://www.youtube.com/watch?v=0aBmb1aaj_Q&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=22

View file

@ -0,0 +1,2 @@
https://www.youtube.com/watch?v=hX612xp_Gtw&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=23

View file

@ -0,0 +1,35 @@
```bash
php spark make:controller Api/Auth --suffix --restful
php spark make:controller Api/Project --suffix --restful
```
![[Pasted image 20241123100630.png]]
![[Pasted image 20241123100706.png]]
![[Pasted image 20241123100734.png]]
![[Pasted image 20241123100756.png]]
--- PROJECT CONTROLLER
![[Pasted image 20241123100834.png]]
![[Pasted image 20241123100851.png]]
![[Pasted image 20241123100913.png]]
ADD SHIELD USERMODEL
![[Pasted image 20241123101019.png]]
```bash
php spark make:model Project --suffix
```
extend allowedFields, e.g.
```php
$allowedFields = ["user_id","name"]
```
Add Project Model to ProjectController
```php
use App\Models\ProjectModel;
```

View file

@ -0,0 +1,22 @@
https://www.youtube.com/watch?v=_ZRHt-fWJpc&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=29
app/Config/Routes.php
Remember: Shield added =>
```php
service('auth')->routes($routes)
```
```php
// API routes (put below service('auth'))
$routes->group("api", ["namespace" => "App\Controller\Api"], function($routes) {
$routes->post("register", "AuthController::register");
$routes->post("login", "AuthController::login");
$routes->get("profile", "AuthController::profile");
$routes->get("logout", "AuthController::logout");
$routes->post("add-project", "ProjectController::addProject");
$routes->get("list-projects", "ProjectController::listProjects");
$routes->delete("delete-project/(:num)", "ProjectController::deleteProject/$1");
});
```

View file

@ -0,0 +1,93 @@
AuthController:
```php
use CodeIgniter\Restful\ResourceController;
use CodeIgniter\Shield\Models\UserModel;
use CodeIgniter\Shield\Entities\User;
class AuthController extends ResourceController
{
//Post
public function register()
{
$rules = [
"username" => "required|is_unique[users.username]",
"email" => "required|valid_email|is_unique[auth_identities.secret]", // gets written to secret field in user table
"password" => "required" // gets written to secret 2 field in user table
];
if (!$this->validate($rules)) {
$response = [
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
];
} else {
$userObject = new UserModel(); // coming from Shield
$userEntityObject = new User([
"username" => $this->request->getVar("username"),
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
]);
$userObject->save($userEntityObject);
$response = [
"status" => true,
"message" => "User saved successfully",
"data" => []
]
}
return $this->respondCreated($response);
}
}
```
Note: shield stores users in auth_identies. Email address should be stored in field secret.
https://onlinewebtutorblog.com/codeigniter-4-restful-api-using-shield-authentication/
My version:
```php
use CodeIgniter\Restful\ResourceController;
use CodeIgniter\Shield\Models\UserModel;
use CodeIgniter\Shield\Entities\User;
class AuthController extends ResourceController
{
//Post
public function register()
{
$rules = [
"username" => "required|is_unique[users.username]",
"email" => "required|valid_email|is_unique[auth_identities.secret]", // gets written to secret field in user table
"password" => "required" // gets written to secret 2 field in user table
];
if (!$this->validate($rules)) {
return $this->respondCreated([
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
]
);
$um = new UserModel(); // coming from Shield
$userEntity = new User([
"username" => $this->request->getVar("username"),
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
]);
$um->save($userEntity);
return $this->respondCreated( [
"status" => true,
"message" => "User saved successfully",
"data" => []
]);
}
}
```

View file

@ -0,0 +1,123 @@
https://www.youtube.com/watch?v=XJHFtfQQmRs&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=31
https://onlinewebtutorblog.com/codeigniter-4-restful-api-using-shield-authentication/
In AuthController::login:
```php
// Post
public function login()
{
if(auth()->loggedIn()){
auth()->logout();
}
$rules = [
"email" => "required|valid_email",
"password" => "required"
];
if (!$this->validate($rules)) {
$response = [
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
];
} else {
// success
$credentials = [
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
];
$loginAttempt = auth()->attempt($credentials);
if (!$loginAttempt->isOK()) {
$response = [
"status" => false,
"message" => "Invalid login details",
"data" => []
];
} else {
// We have a valid data set
$userObject = new UserModel();
$userData = $userObject->findById(auth()->id());
$token = $userData->generateAccessToken("thisismysecretkey");
$auth_token = $token->raw_token; // Only available after generation
$response = [
"status" => true,
"message" => "User logged in successfully",
"data" => [
"token" => $auth_token
]
];
}
}
return $this->respondCreated($response);
}
```
https://shield.codeigniter.com/references/authentication/tokens/
My version:
```php
// Post
public function login()
{
if(auth()->loggedIn()){
auth()->logout();
}
$rules = [
"email" => "required|valid_email",
"password" => "required"
];
if (!$this->validate($rules)) {
return $this->respondCreated([
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
]);
// success
$credentials = [
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
];
$loginAttempt = auth()->attempt($credentials);
if (!$loginAttempt->isOK()) {
return $this->respondCreated([
"status" => false,
"message" => "Invalid login details",
"data" => []
]);
// We have a valid data set
$um = new UserModel();
$userData = $um->findById(auth()->id());
$token = $userData->generateAccessToken("thisismysecretkey");
$auth_token = $token->raw_token; // Only available after generation
return $this->respondCreated( [
"status" => true,
"message" => "User logged in successfully",
"data" => [
"token" => $auth_token
] );
}
```

View file

@ -0,0 +1,61 @@
https://www.youtube.com/watch?v=USqOc-GCA4s&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=32
Create AuthFilter.php
```bash
php spark make:filter Auth --suffix
```
Define before method in AuthFilter.php
```php
public function before(RequestInterface $request, $arguments = null)
{
helper("auth");
if (!auth("tokens")->loggedIn()) {
return redirect()->to(base_url("api/ invalid-access")); // need to create invalid-access route
}
}
```
Routes.php
```php
// API ROUTES
$routes->group("api",["namespace]=> "App\Controllers\Api"], function($routes) {
...
$routes->get("invalid-access", "AuthController::accessDenied");
§routes->get('demo-method", "AuthController::demoMethod",["filter" => "apiauth"]); // Filter Name is defined in aliases array in Filters.php below.
...
```
Define accessDenied method in app/Controllers/Api/AuthController.php
```php
...
public function accessDenied()
{
return $this->respondCreated([
"status" => false,
"message" => "Invalid access",
"data" => []
]);
}
...
```
Add filter to app/Config/Filters.php
```php
use App\Filters\AuthFilter;
public array $aliases = [
'csrf' => CSRF::class,
'toolbar' => DebugToolbar::class,
'honeypot' => Honeypot::class,
'invalidchars' => InvalidChars::class,
'secureheaders' => SecureHeaders::class,
'apiauth' => AuthFilter::class
]
```
Authorize request by adding field "Authorization" with value "Bearer xxxxxx" in Request Header:
![[Pasted image 20241127140801.png]]

View file

@ -0,0 +1,91 @@
https://www.youtube.com/watch?v=f0NifEgwh30&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=33
```php
auth()->user()
```
```php
$userId = auth()->id();
```
![[Pasted image 20241129092837.png]]
AuthController
```php
//...
// Post
public function login()
{
if(auth()->loggedIn()){
auth()->logout();
}
$rules = [
"email" => "required|valid_email",
"password" => "required"
];
if (!$this->validate($rules)) {
$response = [
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
];
} else {
// success
$credentials = [
"email" => $this->request->getVar("email"),
"password" => $this->request->getVar("password")
];
$loginAttempt = auth()->attempt($credentials);
if (!$loginAttempt->isOK()) {
$response = [
"status" => false,
"message" => "Invalid login details",
"data" => []
];
} else {
// to test: directly getting $userObject via auth()->user()
// We have a valid data set
$userObject = new UserModel();
$userData = $userObject->findById(auth()->id());
$token = $userData->generateAccessToken("thisismysecretkey");
$auth_token = $token->raw_token;
$response = [
"status" => true,
"message" => "User logged in successfully",
"data" => [
"token" => $auth_token
]
];
}
}
return $this->respondCreated($response);
}
//...
```

View file

@ -0,0 +1,21 @@
https://www.youtube.com/watch?v=H1KiXEsmsCs&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=34
Routes.php:
```php
//Get
$routes->get("logout", "AuthController::logout", ["filter" => "apiauth"]);
```
AuthController.php
```php
public function logout() {
auth()->logout();
auth()->user()->revokeAllAccessTokens();
return $this->respondCreated([
"status" => true,
"message" => "User logged out successfully",
"data" => []
]);
}
```

View file

@ -0,0 +1,46 @@
https://www.youtube.com/watch?v=104Q76g7DWA&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=36
ProjectController
```php
// Post
public function addProject()
{
$rules = [
"name" => "required",
"budget" => "required"
];
if(!$this->validate($rules)) {
$response = [
"status" => false,
"message" => $this->validator->getErrors(),
"data" => []
];
}else {
$user_id = auth()-id();
$name = $this->request->getVar("name");
$budget = $this->request->getVar("budget");
$pm = new ProjectModel();
$data= [
"user_id" => $user_id,
"name" => name,
"budget" => budget
];
if($pm->insert($data)) {
$response = [
"status" => true,
"message" => "project saved",
"data" => []
];
}else{
$response = [
"status" => false,
"message" => "project save failed",
"data" => []
];
}
}
$return $this->respondCreated($response);
}
```

View file

@ -0,0 +1 @@
https://www.youtube.com/watch?v=B5GafCSXj9U&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=37

View file

@ -0,0 +1,35 @@
https://www.youtube.com/watch?v=-NIoOj-FtHE&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=36
ProjectController.php
```php
public function listProjects()
{
$user_id = auth()->id();
$pm = new ProjectModel();
$projectData = $pm->where([
"user_id" => $user_id
])->findAll();
if (count($projectData)>0) {
$response = [
"status" => true,
"message" => "Project data",
"data" => $projectData
];
}else {
$response = [
"status" => false,
"message" => "No Project data found",
"data" => []
];
}
return $this->respondCreated($response);
}
```
Routes.php
```php
$routes->get("list-projects", "ProjectController::listProjects", ["filter" => "apiauth"]);
```

View file

@ -0,0 +1,98 @@
https://www.youtube.com/watch?v=B5GafCSXj9U&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=37
ProjectController.php
```php
public function deleteProject($project_id)
{
$user_id = auth()->id();
if(!empty($project_id)) {
$pm = new ProjectModel();
$projectData = $pm->where([
"user_id" => $user_id,
"id" => $project_id
])->first();
if (!empty($projectData)) {
if(pm->delete($project_id)) {
$response = [
"status" => true,
"message" => "project deleted",
"data" => []
];
}else {
$response = [
"status" => false,
"message" => "failed to delete project",
"data" => []
];
}
}else{
$response = [
"status" => false,
"message" => "project not found",
"data" => []
];
}
}else{
$response = [
"status" => false,
"message" => "Project Id required",
"data" => []
];
}
return $this->respondCreated($response);
}
```
Routes.php
```php
$routes->delete("delete-project/(:num)", "ProjectController::deleteProject/$1",["filter"=>"apiauth"]);
```
Alternative version:
```php
public function deleteProject($project_id)
{
$user_id = auth()->id();
if(empty($project_id)) {
return $this->respondCreated([
"status" => false,
"message" => "project id required",
"data" => []
]);
}
$pm = new ProjectModel();
$projectData = $pm->where([
"user_id" => $user_id,
"id" => $project_id
])->first();
if(empty($projectData)) {
return $this->respondCreated([
"status" => false,
"message" => "project not found",
"data" => []
]);
}
if(!$pm->delete($project_id)) {
return $this->respondCreated([
"status" => false,
"message" => "failed to delete project",
"data" => []
]);
}
return $this->respondCreated([
"status" => true,
"message" => "project deleted",
"data" => []
]);
}
```

View file

@ -0,0 +1,25 @@
https://www.youtube.com/watch?v=8GhfHZlEaEo&list=PLT9miexWCpPW6Z_OXNv2d78cqCrZaPrVG&index=41
In case Web Server throws CORS errors when trying to access API.
We add a filter that adds header with CORS info to define which kind of HTTP are allowed from foreign source.
Create CorsFilter.php
```bash
php spark make:filter Cors --suffix
```
Add to before method:
```php
public function before(RequestInterface $request, $arguments=null)
{
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization, Content-Type, Accept, API-KEY");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH");
}
```
Add in app/Config/Filters.php:
![[Pasted image 20241202084231.png]]
![[Pasted image 20241202084303.png]]