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,68 @@
Source:
[Setup CodeIgniter — Devilbox 1.0 documentation](https://devilbox.readthedocs.io/en/latest/examples/setup-codeigniter.html?highlight=CodeIgniter)
Prerequisites: Have correct docker compose installed:
```bash
sudo apt install docker-compose-v2
```
Download Devilbox
Remove unwanted hosts from docker-compose.yml file
copy env file to .env
Set TLD_SUFFIX=local
In /etc/hosts, add 127.0.01 with application URL:
127.0.0.1 verleihapp.local
Start docker container: sudo docker compose up -d
Enter Container: ./shell.sh
Install CodeIgniter4 and create htdocs link:
```bash
mkdir myproject
cd myproject
composer create-project codeigniter4/appstarter myprojectapp
ln -s myprojectapp/public htdocs
```
.env settings
```php
CI_ENVIRONMENT = development (instead of production)
app.baseURL = 'http://myproject.local'
database.default.hostname = myproject.local
database.default.database = myproject
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
```
Access mysql from inside container
```bash
./shell.sh
mysql -h 127.0.0.1 -u root
CREATE DATABASE godotweb;
```
https://shield.codeigniter.com/getting_started/install/

View file

@ -0,0 +1,2 @@
docker-compose up -d
./shell.sh

View file

@ -0,0 +1,5 @@
```bash
$ grep -R CI_VERSION|grep const
framework/system/CodeIgniter.php: public const CI_VERSION = '4.5.5';
```

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]]

View file

@ -0,0 +1,3 @@
```bash
python3 -m http.server 8000
```

View file

@ -0,0 +1,20 @@
```php
<?php
$DBUSER="user";
$DBPASSWD="password";
$DATABASE="user_db";
$filename = "backup-" . date("d-m-Y") . ".sql.gz";
$mime = "application/x-gzip";
header( "Content-Type: " . $mime );
header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
$cmd = "mysqldump -u $DBUSER --password=$DBPASSWD $DATABASE | gzip --best";
passthru( $cmd );
exit(0);
?>
```

View file

@ -0,0 +1,4 @@
developer.tomtom.com
tschneider
Supertomtom1!

View file

@ -0,0 +1,44 @@
```php
<!-- test1.php -->
<?php
//The URL with parameters / query string.
// Escape: $str = preg_replace('/[^a-z\d ]/i', '', $str);
$url='https://api.tomtom.com/search/2/search/Am%20Kapellchen%2021%2C%2041470%20Neuss.json?lat=37.337&lon=-121.89&minFuzzyLevel=1&maxFuzzyLevel=2&view=Unified&relatedPois=off&key=xcA6NjLwDPmayP6y56AoVoloz1iohbUV';
//we use file_get_contents to GET the URL in question.
$contents = file_get_contents($url);
$result = json_decode($contents);
$lat = $result->results[0]->position->lat;
$lon = $result->results[0]->position->lon;
echo "Lat=" . $lat . ", Lon=" . $lon;
```
````php
<?php
//The URL with parameters / query string.
$url='https://api.tomtom.com/search/2/search/Am%20Kapellchen%2021%2C%2041470%20Neuss.json?lat=37.337&lon=-121.89&minFuzzyLevel=1&maxFuzzyLevel=2&view=Unified&relatedPois=off&key=xcA6NjLwDPmayP6y56AoVoloz1iohbUV';
//we use file_get_contents to GET the URL in question.
$contents = file_get_contents($url);
//If $contents is not a boolean FALSE value.
if($contents !== false){
//Print out the contents.
echo $contents;
}
```
````

View file

@ -0,0 +1,146 @@
````php
<!DOCTYPE html>
<html class='use-all-space'>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=Edge' />
<meta charset='UTF-8'>
<title>Maps SDK for Web - Static route</title>
<meta name='viewport'
content='width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no'/>
<link rel='stylesheet' type='text/css' href='https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.20.0/maps/maps.css'>
<link rel='stylesheet' type='text/css' href='../test/assets/ui-library/icons-css/routing.css'/>
<link rel='stylesheet' type='text/css' href='../test/assets/ui-library/index.css'/>
</head>
<style>
.icon {
background-size: cover;
height: 30px;
width: 30px;
}
.route-marker {
align-items: center;
background-color: #4a90e2;
border: solid 3px #2faaff;
border-radius: 50%;
display: flex;
height: 32px;
justify-content: center;
transition: width .1s, height .1s;
width: 32px;
}
</style>
<body>
<div><h1>TEST KARTE</<h1></div>
<div style="height: 90%" id='map' class='map'></div>
<script src='https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.20.0/maps/maps-web.min.js'></script>
<script src='https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.20.0/services/services-web.min.js'></script>
<script type='text/javascript' src='../test/assets/js/mobile-or-tablet.js'></script>
<script>
var map = tt.map({
key: 'xcA6NjLwDPmayP6y56AoVoloz1iohbUV',
container: 'map',
//dragPan: !isMobileOrTablet()
dragPan: false
});
map.scrollZoom.disable()
//map.addControl(new tt.FullscreenControl());
//map.addControl(new tt.NavigationControl());
function createMarkerElement(type) {
var element = document.createElement('div');
var innerElement = document.createElement('div');
element.className = 'route-marker';
innerElement.className = 'icon tt-icon -white -' + type;
element.appendChild(innerElement);
return element;
}
function addMarkers(feature) {
var startPoint, endPoint;
if (feature.geometry.type === 'MultiLineString') {
startPoint = feature.geometry.coordinates[0][0]; //get first point from first line
endPoint = feature.geometry.coordinates.slice(-1)[0].slice(-1)[0]; //get last point from last line
} else {
startPoint = feature.geometry.coordinates[0];
endPoint = feature.geometry.coordinates.slice(-1)[0];
}
new tt.Marker({ element: createMarkerElement('start') }).setLngLat(startPoint).addTo(map);
new tt.Marker({ element: createMarkerElement('finish') }).setLngLat(endPoint).addTo(map);
}
function findFirstBuildingLayerId() {
var layers = map.getStyle().layers;
for (var index in layers) {
if (layers[index].type === 'fill-extrusion') {
return layers[index].id;
}
}
throw new Error('Map style does not contain any layer with fill-extrusion type.');
}
map.once('load', function() {
tt.services.calculateRoute({
key: 'xcA6NjLwDPmayP6y56AoVoloz1iohbUV',
traffic: false,
locations: '4.8786,52.3679:4.8798,52.3679'
})
.then(function(response) {
var geojson = response.toGeoJson();
map.addLayer({
'id': 'route',
'type': 'line',
'source': {
'type': 'geojson',
'data': geojson
},
'paint': {
'line-color': '#4a90e2',
'line-width': 8
}
}, findFirstBuildingLayerId());
addMarkers(geojson.features[0]);
var bounds = new tt.LngLatBounds();
geojson.features[0].geometry.coordinates.forEach(function(point) {
bounds.extend(tt.LngLat.convert(point));
});
map.fitBounds(bounds, { duration: 0, padding: 50 });
});
});
</script>
</body>
</html>
```