├── .babelrc
├── .env-example
├── .gitignore
├── Readme.md
├── app
├── controllers
│ ├── Contact.php
│ ├── Home.php
│ ├── Login.php
│ ├── Maintenance.php
│ ├── Password.php
│ ├── User.php
│ ├── UserImage.php
│ └── Users.php
├── core
│ └── controller.php
├── database
│ ├── connect.php
│ ├── no-query-builder
│ │ ├── create.php
│ │ ├── delete.php
│ │ ├── read.php
│ │ └── update.php
│ ├── queries.php
│ └── query-builder
│ │ ├── execute.php
│ │ ├── join.php
│ │ ├── limit.php
│ │ ├── order.php
│ │ ├── paginate.php
│ │ ├── read.php
│ │ ├── search.php
│ │ └── where.php
├── helpers
│ ├── constants.php
│ ├── csrf.php
│ ├── email.php
│ ├── flash.php
│ ├── helpers.php
│ ├── image.php
│ ├── old.php
│ ├── redirect.php
│ ├── sessions.php
│ ├── validate.php
│ └── validations.php
├── router
│ ├── router.php
│ └── routes.php
└── views
│ ├── contact.php
│ ├── create.php
│ ├── edit.php
│ ├── emails
│ ├── contact.html
│ └── password.html
│ ├── home.php
│ ├── login.php
│ ├── maintenance.php
│ ├── master.php
│ └── partials
│ └── header.php
├── composer.json
├── composer.lock
├── package-lock.json
├── package.json
├── public
├── .DS_Store
├── app.js
├── app.js.map
├── assets
│ ├── .DS_Store
│ ├── css
│ │ └── styles.css
│ └── js
│ │ ├── alpine-components
│ │ └── users.js
│ │ ├── app.js
│ │ ├── http.js
│ │ ├── teste.js
│ │ └── users.js
├── bootstrap.php
├── index.php
└── maintenance.php
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
4 |
--------------------------------------------------------------------------------
/.env-example:
--------------------------------------------------------------------------------
1 | MAINTENANCE=
2 | PRODUCTION=
3 |
4 | DATABASE_HOST=
5 | DATABASE_USER=
6 | DATABASE_PASSWORD=
7 | DATABASE_NAME=
8 |
9 | EMAIL_HOST=
10 | EMAIL_USERNAME=
11 | EMAIL_PASSWORD=
12 | EMAIL_PORT=
13 |
14 | TONAME=
15 | TOEMAIL=
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | .idea
3 | node_modules
4 | .DS_Store
5 | .env
6 | *.png
7 | *.jpeg
8 | *.jpg
9 | *.gif
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## Curso PHP Profissional do Clube Full-Stack
2 |
3 | ### 🚀 Links Importantes
4 |
5 | 1. [Youtube](https://www.youtube.com/c/AlexandreCardoso)
6 | 2. [Adquirir Curso](https://bit.ly/php-profissional-clube-fullstack)
7 |
8 | ### 🔥 Para rodar o projeto
9 |
10 | 1. composer install - Para instalar as dependências do composer
11 | 2. npm install - Para instalar as dependências do npm
12 | 3. php -S localhost:8000 - Para iniciar o servidor do php
13 | 4. npm run dev - Para rodar o webpack
14 | 5. Mudar o banco de dados no arquivo .env - Para mudar o bando de dados
15 |
--------------------------------------------------------------------------------
/app/controllers/Contact.php:
--------------------------------------------------------------------------------
1 | 'contact',
13 | 'data' => ['title' => 'Contact',],
14 | ];
15 | }
16 |
17 | public function store()
18 | {
19 | // $email = new stdClass();
20 | // $email->fromName = 'Alexandre';
21 | // $email->fromEmail = 'xandecar@hotmail.com';
22 | // $email->toName = 'Joao';
23 | // $email->toEmail = 'joao@email.com.br';
24 | // $email->subject = 'teste de mensagem';
25 | // $email->message = 'mensagem simples';
26 | // $email->template = 'contact';
27 |
28 | $validated = validate([
29 | 'name' => 'required',
30 | 'email' => 'required|email',
31 | 'subject' => 'required',
32 | 'message' => 'required'
33 | ], persistInputs:true, checkCsrf:true);
34 |
35 | if (!$validated) {
36 | return redirect('/contact');
37 | }
38 |
39 | $sent = send([
40 | 'fromName' => $validated['name'],
41 | 'fromEmail' => $validated['email'],
42 | 'toName' => $_ENV['TONAME'],
43 | 'toEmail' => $_ENV['TOEMAIL'],
44 | 'subject' => $validated['subject'],
45 | 'message' => $validated['message'],
46 | 'template' => 'contact'
47 | ]);
48 |
49 | if ($sent) {
50 | return setMessageAndRedirect('contact_success', 'Enviado com sucesso', '/contact');
51 | }
52 | return setMessageAndRedirect('contact_error', 'Ocorreu um erro ao enviar o email, tente novamente em alguns segundos', '/contact');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/controllers/Home.php:
--------------------------------------------------------------------------------
1 | $search]);
15 | }
16 |
17 | paginate(5);
18 |
19 | // where('id', '<', 20);
20 | // whereIn('firstName', ['Alexandre','Prof. Lulu Ullrich','Loma Champlin']);
21 |
22 | // if ($search) {
23 | // search(['firstName' => $search,'lastName' => $search]);
24 | // }
25 |
26 | // limit(10);
27 |
28 |
29 | // select * from users where firstName like %alexandre% or lastName like %alexandre% or age
30 |
31 | $users = execute();
32 |
33 | // dd($users);
34 |
35 | // dd($users);
36 |
37 | // dd($users);
38 |
39 | // select * from users order by id desc limit 10 offset 0
40 |
41 | // dd($users);
42 |
43 | return [
44 | 'view' => 'home',
45 | 'data' => ['title' => 'Home', 'users' => $users,'links' => render()],
46 | ];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/controllers/Login.php:
--------------------------------------------------------------------------------
1 | 'login',
11 | 'data' => ['title' => 'Login']
12 | ];
13 | }
14 |
15 | public function store()
16 | {
17 | $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
18 | $password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING);
19 |
20 | if (empty($email) || empty($password)) {
21 | return setMessageAndRedirect('message', 'Usuário ou senha inválidos', '/login');
22 | }
23 |
24 | // $user = findBy('users', 'email', $email);
25 |
26 | read('users', 'users.id,firstName,lastName,email,password,path');
27 | tableJoin('photos', 'id', 'left');
28 | where('email', $email);
29 |
30 | $user = execute(isFetchAll:false);
31 |
32 | // dd($user);
33 |
34 | if (!$user) {
35 | return setMessageAndRedirect('message', 'Usuário ou senha inválidos', '/login');
36 | }
37 |
38 | if (!password_verify($password, $user->password)) {
39 | return setMessageAndRedirect('message', 'Usuário ou senha inválidos', '/login');
40 | }
41 |
42 | unset($user->password);
43 |
44 | $_SESSION[LOGGED] = $user;
45 |
46 | return redirect('/');
47 | }
48 |
49 | public function destroy()
50 | {
51 | unset($_SESSION[LOGGED]);
52 |
53 | return redirect('/');
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/controllers/Maintenance.php:
--------------------------------------------------------------------------------
1 | 'maintenance',
11 | 'data' => ['title' => 'Em manutenção']
12 | ];
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/controllers/Password.php:
--------------------------------------------------------------------------------
1 | id) {
10 | return redirect('/');
11 | }
12 |
13 | $validated = validate([
14 | 'email' => 'required|confirmed',
15 | 'email_confirmation' => 'required'
16 | ], checkCsrf: true);
17 |
18 |
19 | if (!$validated) {
20 | return redirect('/user/edit/profile');
21 | }
22 |
23 | dd($validated);
24 | $updated = update('users', [
25 | 'password' => $validated['password']
26 | ], ['id' => user()->id]);
27 |
28 | if ($updated) {
29 | $user = user();
30 | send([
31 | 'fromName' => 'Alexandre',
32 | 'fromEmail' => 'xandecar@hotmail.com',
33 | 'toName' => $user->firstName,
34 | 'toEmail' => $user->email,
35 | 'subject' => 'Senha alterada',
36 | 'message' => 'Senha alterada com sucesso',
37 | 'template' => 'password'
38 | ]);
39 | return setMessageAndRedirect('password_success', 'Senha alterada com sucesso', "/user/edit/profile");
40 | } else {
41 | return setMessageAndRedirect('password_error', 'Ocorreu um erro ao atualizar a senha ', "/user/edit/profile");
42 | }
43 |
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/app/controllers/User.php:
--------------------------------------------------------------------------------
1 | id);
27 |
28 | $user = execute(isFetchAll:false);
29 |
30 | return [
31 | 'view' => 'edit',
32 | 'data' => ['title' => 'Edit','user' => $user]
33 | ];
34 | }
35 |
36 | public function create():array
37 | {
38 | return [
39 | 'view' => 'create',
40 | 'data' => ['title' => 'Create']
41 | ];
42 | }
43 |
44 | public function store()
45 | {
46 | $validate = validate([
47 | 'firstName' => 'required',
48 | 'lastName' => 'required',
49 | 'email' => 'required|email|unique:users',
50 | 'password' => 'maxlen:5|required',
51 | ], persistInputs:true, checkCsrf:true);
52 |
53 | if (!$validate) {
54 | return redirect('/user/create');
55 | }
56 |
57 | $validate['password'] = password_hash($validate['password'], PASSWORD_DEFAULT);
58 |
59 | $created = create('users', $validate);
60 |
61 | if (!$created) {
62 | setFlash('message', 'Ocorreu um erro ao cadastrar, tente novamente em alguns segundo');
63 | return redirect('/user/create');
64 | }
65 |
66 | return redirect('/');
67 | }
68 |
69 | public function update($args)
70 | {
71 | if (!isset($args['user']) || $args['user'] !== user()->id) {
72 | return redirect('/');
73 | }
74 |
75 | $validated = validate([
76 | 'firstName' => 'required',
77 | 'lastName' => 'required',
78 | 'email' => 'required|email|uniqueUpdate:users,id='.$args['user']
79 | ]);
80 |
81 | if (!$validated) {
82 | return redirect('/user/edit/profile');
83 | }
84 |
85 | $updated = update('users', $validated, ['id' => user()->id]);
86 |
87 | if ($updated) {
88 | return setMessageAndRedirect('updated_success', 'Atualizado com sucesso', '/user/edit/profile');
89 | }
90 | setMessageAndRedirect('updated_error', 'Ocorreu um erro ao atualizar', '/user/edit/profile');
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/controllers/UserImage.php:
--------------------------------------------------------------------------------
1 | id);
15 |
16 | $photoUser = execute(isFetchAll:false);
17 |
18 | if ($photoUser) {
19 | $updated = update('photos', [
20 | 'path' => $path
21 | ], [
22 | 'userId' => $auth->id
23 | ]);
24 | @unlink($photoUser->path);
25 | } else {
26 | $updated = create('photos', [
27 | 'userId' => $auth->id,
28 | 'path' => $path
29 | ]);
30 | }
31 |
32 | if ($updated) {
33 | $auth->path = $path;
34 | setMessageAndRedirect('upload_success', 'Upload feito com sucesso', '/user/edit/profile');
35 | return;
36 | }
37 | setMessageAndRedirect('upload_error', 'Ocorreu um erro ao fazer o upload', '/user/edit/profile');
38 | } catch (\Exception $e) {
39 | setMessageAndRedirect('upload_error', $e->getMessage(), '/user/edit/profile');
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/controllers/Users.php:
--------------------------------------------------------------------------------
1 | $method($params);
20 |
21 | if ($_SERVER['REQUEST_METHOD'] === 'POST') {
22 | die();
23 | }
24 |
25 | return $controller;
26 | }
27 |
--------------------------------------------------------------------------------
/app/database/connect.php:
--------------------------------------------------------------------------------
1 | PDO::FETCH_OBJ
11 | ]
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/app/database/no-query-builder/create.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
17 | return $prepare->execute($data);
18 | } catch (PDOException $e) {
19 | var_dump($e->getMessage());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/database/no-query-builder/delete.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
17 | $prepare->execute($where);
18 | return $prepare->rowCount();
19 | }
20 |
--------------------------------------------------------------------------------
/app/database/no-query-builder/read.php:
--------------------------------------------------------------------------------
1 | query("select {$fields} from {$table}");
9 | return $query->fetchAll();
10 | } catch (PDOException $e) {
11 | var_dump($e->getMessage());
12 | }
13 | }
14 |
15 | function findBy($table, $field, $value, $fields = '*')
16 | {
17 | try {
18 | $connect = connect();
19 | $prepare = $connect->prepare("select {$fields} from {$table} where {$field} = :{$field}");
20 | $prepare->execute([
21 | $field => $value
22 | ]);
23 |
24 | return $prepare->fetch();
25 | } catch (PDOException $e) {
26 | var_dump($e->getMessage());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/database/no-query-builder/update.php:
--------------------------------------------------------------------------------
1 | prepare($sql);
25 | $prepare->execute($data);
26 | return $prepare->rowCount();
27 |
28 | // dd($sql, $data);
29 | }
30 |
--------------------------------------------------------------------------------
/app/database/queries.php:
--------------------------------------------------------------------------------
1 | prepare($query['sql']);
19 | $prepare->execute($query['execute'] ?? []);
20 |
21 | if ($rowCount) {
22 | $query['count'] = $prepare->rowCount();
23 | return $query['count'];
24 | }
25 |
26 | if ($isFetchAll) {
27 | return (object)[
28 | 'count' => $query['count'] ?? $prepare->rowCount(),
29 | 'rows' => $prepare->fetchAll()
30 | ];
31 | }
32 |
33 | return $prepare->fetch();
34 | } catch (Exception $e) {
35 | // $message = "Erro no arquivo {$e->getFile()} na linha {$e->getLine()} com a mensagem: {$e->getMessage()}";
36 | // $message.= $query['sql'];
37 | $error = [
38 | 'file' => $e->getFile(),
39 | 'line' => $e->getLine(),
40 | 'message' => $e->getMessage(),
41 | 'sql' => $query['sql'],
42 | ];
43 |
44 | ddd($error);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/database/query-builder/join.php:
--------------------------------------------------------------------------------
1 | build();
8 | $tableToSingular = $inflector->singularize($table);
9 |
10 | return $tableToSingular.ucfirst($field);
11 | }
12 |
13 |
14 | function tableJoin(string $table, string $fieldFK, string $typeJoin = 'inner')
15 | {
16 | global $query;
17 |
18 | if (isset($query['where'])) {
19 | throw new Exception("Nao posso colocar o where antes do join");
20 | }
21 |
22 | $fkToJoin = fieldFK($query['table'], $fieldFK);
23 |
24 | $query['sql'] = "{$query['sql']} {$typeJoin} join {$table} on {$table}.{$fkToJoin} = {$query['table']}.{$fieldFK}";
25 | }
26 |
27 | function tableJoinWithFK(string $table, string $fieldFK, string $typeJoin = 'inner')
28 | {
29 | global $query;
30 |
31 | if (isset($query['where'])) {
32 | throw new Exception("Nao posso colocar o where antes do join");
33 | }
34 |
35 | $fkToJoin = fieldFK($table, $fieldFK);
36 |
37 | $query['sql'] = "{$query['sql']} {$typeJoin} join {$table} on {$table}.{$fieldFK} = {$query['table']}.{$fkToJoin}";
38 | }
39 |
--------------------------------------------------------------------------------
/app/database/query-builder/limit.php:
--------------------------------------------------------------------------------
1 | ';
39 |
40 | if ($currentPage > 1) {
41 | $previous = $currentPage - 1;
42 | $linkPage = http_build_query(array_merge($_GET, ['page' => $previous]));
43 | $first = http_build_query(array_merge($_GET, ['page' => 1]));
44 | $links.= "
Primeira";
45 | $links.= "Anterior";
46 | }
47 |
48 | $class = '';
49 | // 1 - 5 = -4 1 + 5 = 6
50 | // 7 - 5 = 2 . 7+5 = 12
51 | for ($i=$currentPage - $maxLinks; $i<=$currentPage + $maxLinks ; $i++) {
52 | // $page = "?page={$i}";
53 | if ($i > 0 && $i <= $pageCount) {
54 | $class = $currentPage === $i ? 'active' : '';
55 | $linkPage = http_build_query(array_merge($_GET, ['page' => $i]));
56 | $links.= "{$i}";
57 | }
58 | }
59 |
60 | if ($currentPage < $pageCount) {
61 | $next = $currentPage + 1;
62 | $linkPage = http_build_query(array_merge($_GET, ['page' => $next]));
63 | $last = http_build_query(array_merge($_GET, ['page' => $pageCount]));
64 | $links.= "Próxima";
65 | $links.= "Última";
66 | }
67 |
68 | $links .= '';
69 |
70 | return $links;
71 | }
72 |
--------------------------------------------------------------------------------
/app/database/query-builder/read.php:
--------------------------------------------------------------------------------
1 | $searched) {
19 | $sql.= "{$field} like :{$field} or ";
20 | $execute[$field] = "%{$searched}%";
21 | }
22 |
23 | $sql = rtrim($sql, ' or ');
24 |
25 | $query['sql'] = $sql;
26 | $query['execute'] = $execute;
27 | }
28 |
--------------------------------------------------------------------------------
/app/database/query-builder/where.php:
--------------------------------------------------------------------------------
1 | 3) {
19 | throw new Exception('O where precisa de 2 ou 3 parâmetros');
20 | }
21 |
22 | if ($numArgs === 2) {
23 | $field = $args[0];
24 | $operator = '=';
25 | $value = $args[1];
26 | }
27 |
28 | if ($numArgs === 3) {
29 | $field = $args[0];
30 | $operator = $args[1];
31 | $value = $args[2];
32 | }
33 |
34 | $fieldWhere = $field;
35 |
36 | if (str_contains($field, '.')) {
37 | [, $fieldWhere] = explode('.', $field);
38 | }
39 |
40 | $query['where'] = true;
41 | $query['execute'] = array_merge($query['execute'], [$fieldWhere => $value]);
42 | $query['sql'] = "{$query['sql']} where {$field} {$operator} :{$fieldWhere}";
43 | }
44 |
45 |
46 | function orWhere()
47 | {
48 | global $query;
49 |
50 | $args = func_get_args();
51 | $numArgs = func_num_args();
52 |
53 |
54 | if (!isset($query['read'])) {
55 | throw new Exception('Antes de chamar o where chame o read');
56 | }
57 |
58 | if (!isset($query['where'])) {
59 | throw new Exception('Antes de chamar o orWhere chame o where');
60 | }
61 |
62 | if ($numArgs < 2 || $numArgs > 4) {
63 | throw new Exception('O where precisa de 2 até 4 parâmetros');
64 | }
65 |
66 | $data = match ($numArgs) {
67 | 2 => whereTwoParameters($args),
68 | 3 => whereThreeParameters($args),
69 | 4 => $args,
70 | };
71 |
72 | [$field, $operator, $value, $typeWhere] = $data;
73 |
74 | // dd([$field => $value]);
75 | $query['where'] = true;
76 | $query['execute'] = array_merge($query['execute'], [$field => $value]);
77 | $query['sql'] = "{$query['sql']} {$typeWhere} {$field} {$operator} :{$field}";
78 | }
79 |
80 | function whereTwoParameters(array $args): array
81 | {
82 | $field = $args[0];
83 | $operator = '=';
84 | $value = $args[1];
85 | $typeWhere = 'or';
86 |
87 | return [$field,$operator,$value, $typeWhere];
88 | }
89 | function whereThreeParameters(array $args): array
90 | {
91 | $operators = ['=','<','>','!==','<=','>='];
92 | $field = $args[0];
93 | $operator = in_array($args[1], $operators) ? $args[1] : '=';
94 | $value = in_array($args[1], $operators) ? $args[2] : $args[1];
95 | $typeWhere = $args[2] === 'and' ? 'and' : 'or';
96 |
97 | return [$field,$operator,$value, $typeWhere];
98 | }
99 |
100 | function whereIn(string $field, array $data)
101 | {
102 | global $query;
103 |
104 | if (isset($query['where'])) {
105 | throw new Exception("Não poder ter chamado a função where com a função where in");
106 | }
107 |
108 | $query['where'] = true;
109 | $query['sql'] = "{$query['sql']} where {$field} in (".'\''.implode('\',\'', $data).'\''.')';
110 | }
111 |
112 |
113 | // function where(string $field, string $operator, string|int $value)
114 | // {
115 | // global $query;
116 |
117 | // if (!isset($query['read'])) {
118 | // throw new Exception('Antes de chamar o where chame o read');
119 | // }
120 |
121 | // if (func_num_args() !== 3) {
122 | // throw new Exception('O where precisa de exatamente 3 parâmetros');
123 | // }
124 |
125 | // $query['where'] = true;
126 | // $query['execute'] = array_merge($query['execute'], [$field => $value]);
127 | // $query['sql'] = "{$query['sql']} where {$field} {$operator} :{$field}";
128 | // }
129 |
130 | // function orWhere(string $field, string $operator, string|int $value, string $typeWhere ='or')
131 | // {
132 | // global $query;
133 |
134 | // if (!isset($query['read'])) {
135 | // throw new Exception('Antes de chamar o where chame o read');
136 | // }
137 |
138 | // if (!isset($query['where'])) {
139 | // throw new Exception('Antes de chamar o orWhere chame o where');
140 | // }
141 |
142 | // if (func_num_args() < 3 or func_num_args() > 4) {
143 | // throw new Exception('O where precisa 3 ou 4 parâmetros');
144 | // }
145 |
146 | // $query['where'] = true;
147 | // $query['execute'] = array_merge($query['execute'], [$field => $value]);
148 | // $query['sql'] = "{$query['sql']} {$typeWhere} {$field} {$operator} :{$field}";
149 | // }
150 |
--------------------------------------------------------------------------------
/app/helpers/constants.php:
--------------------------------------------------------------------------------
1 | ";
9 | }
10 |
11 | function checkCsrf()
12 | {
13 | $csrf = filter_input(INPUT_POST, 'csrf', FILTER_SANITIZE_STRING);
14 |
15 | if (!$csrf) {
16 | throw new Exception('Token inválido');
17 | }
18 |
19 | if (!isset($_SESSION['csrf'])) {
20 | throw new Exception('Token inválido');
21 | }
22 |
23 | if ($csrf !== $_SESSION['csrf']) {
24 | throw new Exception('Token inválido');
25 | }
26 |
27 | unset($_SESSION['csrf']);
28 | }
29 |
--------------------------------------------------------------------------------
/app/helpers/email.php:
--------------------------------------------------------------------------------
1 | isSMTP();
9 | $phpmailer->Host = $_ENV['EMAIL_HOST'];
10 | $phpmailer->SMTPAuth = true;
11 | $phpmailer->Port = $_ENV['EMAIL_PORT'];
12 | $phpmailer->Username = $_ENV['EMAIL_USERNAME'];
13 | $phpmailer->Password = $_ENV['EMAIL_PASSWORD'];
14 |
15 | return $phpmailer;
16 | }
17 |
18 | function send(stdClass|array $emailData)
19 | {
20 | try {
21 | if (is_array($emailData)) {
22 | $emailData = (object) $emailData;
23 | }
24 |
25 | $body = (isset($emailData->template)) ? template($emailData) : $emailData->message;
26 |
27 | checkPropertiesEmail($emailData);
28 |
29 | $mail = config();
30 | $mail->setFrom($emailData->fromEmail, $emailData->fromName);
31 | $mail->addAddress($emailData->toEmail, $emailData->toName);
32 |
33 | $mail->isHTML(true);
34 | $mail->CharSet = 'UTF-8';
35 | $mail->Subject = $emailData->subject;
36 | $mail->Body = $body;
37 | $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
38 |
39 | return $mail->send();
40 | } catch (Exception $e) {
41 | dd($e->getMessage());
42 | }
43 | }
44 |
45 | function checkPropertiesEmail($emailData)
46 | {
47 | $propertiesRequired = ['toName','toEmail','fromName','fromEmail','subject','message'];
48 | unset($emailData->template);
49 |
50 | $emailVars = get_object_vars($emailData);
51 |
52 | foreach ($propertiesRequired as $prop) {
53 | if (!array_key_exists($prop, $emailVars)) {
54 | throw new Exception("{$prop} é obrigatório para enviar o email");
55 | }
56 | }
57 | }
58 |
59 |
60 | function template($emailData)
61 | {
62 | $templateFile = ROOT."/app/views/emails/{$emailData->template}.html";
63 |
64 | if (!file_exists($templateFile)) {
65 | throw new Exception("O template {$emailData->template}.html não existe");
66 | }
67 |
68 | $template = file_get_contents($templateFile);
69 |
70 | $emailVars = get_object_vars($emailData);
71 |
72 | $arr = array_map(function ($key) {
73 | return "@{$key}";
74 | }, array_keys($emailVars));
75 |
76 | // dd($arr);
77 |
78 | // $vars = [];
79 |
80 | // foreach ($emailVars as $key => $value) {
81 | // $vars["@{$key}"] = $value;
82 | // }
83 |
84 | return str_replace($arr, array_values($emailVars), $template);
85 | }
86 |
--------------------------------------------------------------------------------
/app/helpers/flash.php:
--------------------------------------------------------------------------------
1 | $flash";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/helpers/helpers.php:
--------------------------------------------------------------------------------
1 | ['imagecreatefrompng', 'imagepng'],
12 | 'jpg', 'jpeg' => ['imagecreatefromjpeg', 'imagejpeg'],
13 | 'gif' => ['imagecreatefromgif', 'imagegif'],
14 | };
15 | }
16 |
17 | function isFileToUpload($fieldName)
18 | {
19 | if (!isset($_FILES[$fieldName], $_FILES[$fieldName]['name']) || $_FILES[$fieldName]['name'] === '') {
20 | throw new Exception("O campo {$fieldName} não existe ou não foi escolhida uma imagem");
21 | }
22 | }
23 |
24 | function isImage($extension)
25 | {
26 | $acceptedExtensions = ['jpeg', 'jpg', 'gif', 'png'];
27 | if (!in_array($extension, $acceptedExtensions)) {
28 | $extensions = implode(',', $acceptedExtensions);
29 | throw new Exception("O arquivo não é aceito, aceitamos somente {$extensions}");
30 | }
31 | }
32 |
33 | function resize(int $width, int $height, int $newWidth, int $newHeight)
34 | {
35 | $ratio = $width / $height;
36 |
37 | ($newWidth / $newHeight > $ratio) ?
38 | $newWidth = $newHeight * $ratio :
39 | $newHeight = $newWidth / $ratio;
40 |
41 | return [$newWidth, $newHeight];
42 | }
43 |
44 | function crop(int $width, int $height, int $newWidth, int $newHeight)
45 | {
46 | $thumbWidth = $newWidth;
47 | $thumbHeight = $newHeight;
48 |
49 | $srcAspect = $width / $height;
50 | $dstAspect = $thumbWidth / $thumbHeight;
51 |
52 | ($srcAspect >= $dstAspect) ?
53 | $newWidth = $width / ($height / $thumbHeight) :
54 | $newHeight = $height / ($width / $thumbWidth);
55 |
56 | return [$newWidth, $newHeight, $thumbWidth, $thumbHeight];
57 | }
58 |
59 | function upload(int $newWidth, int $newHeight, string $folder, string $type = 'resize')
60 | {
61 | isFileToUpload('file');
62 |
63 | $extension = getExtension($_FILES['file']['name']);
64 |
65 | isImage($extension);
66 |
67 | [$width, $height] = getimagesize($_FILES['file']['tmp_name']);
68 |
69 | [$functionCrateFrom, $saveImage] = getFunctionCreateFrom($extension);
70 |
71 | $src = $functionCrateFrom($_FILES['file']['tmp_name']);
72 |
73 | if ($type === 'resize') {
74 | [$newWidth, $newHeight] = resize($width, $height, $newWidth, $newHeight);
75 | $dst = imagecreatetruecolor($newWidth, $newHeight);
76 | imagecopyresampled($dst, $src, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
77 | } else {
78 | [$newWidth, $newHeight, $thumbWidth, $thumbHeight] = crop($width, $height, $newWidth, $newHeight);
79 | $dst = imagecreatetruecolor($thumbWidth, $thumbHeight);
80 | imagecopyresampled(
81 | $dst,
82 | $src,
83 | 0 - ($newWidth - $thumbWidth) / 2,
84 | 0 - ($newHeight - $thumbHeight) / 2,
85 | 0,
86 | 0,
87 | $newWidth,
88 | $newHeight,
89 | $width,
90 | $height
91 | );
92 | }
93 |
94 | $path = $folder . DIRECTORY_SEPARATOR . rand() . '.' . $extension;
95 |
96 | $saveImage($dst, $path);
97 |
98 | return $path;
99 | }
100 |
--------------------------------------------------------------------------------
/app/helpers/old.php:
--------------------------------------------------------------------------------
1 | $validate) {
12 | $result[$field] = (!str_contains($validate, '|')) ?
13 | singleValidation($validate, $field, $param) :
14 | multipleValidations($validate, $field, $param);
15 | }
16 |
17 | if ($persistInputs) {
18 | setOld();
19 | }
20 |
21 | if (in_array(false, $result, true)) {
22 | return false;
23 | }
24 |
25 | return $result;
26 | }
27 |
28 | function singleValidation($validate, $field, $param)
29 | {
30 | if (str_contains($validate, ':')) {
31 | [$validate, $param] = explode(':', $validate);
32 | }
33 | return $validate($field, $param);
34 | }
35 |
36 | function multipleValidations($validate, $field, $param)
37 | {
38 | $explodePipeValidate = explode('|', $validate);
39 | $result = [];
40 | foreach ($explodePipeValidate as $validate) {
41 | if (str_contains($validate, ':')) {
42 | [$validate, $param] = explode(':', $validate);
43 | }
44 |
45 | $result[$field] = $validate($field, $param);
46 |
47 | if ($result[$field] === false || $result[$field] === null) {
48 | break;
49 | }
50 | }
51 | return $result[$field];
52 | }
53 |
--------------------------------------------------------------------------------
/app/helpers/validations.php:
--------------------------------------------------------------------------------
1 | $param) {
84 | setFlash($field, "Esse campo não pode passar de {$param} caracteres");
85 | return false;
86 | }
87 |
88 | return $data;
89 | }
90 |
91 | function optional($field)
92 | {
93 | // $data = filter_input(INPUT_POST, $field, FILTER_SANITIZE_STRING);
94 | $data = strip_tags($_POST[$field]);
95 |
96 | if ($data === '') {
97 | return null;
98 | }
99 |
100 | return $data;
101 | }
102 |
103 | function confirmed($field){
104 |
105 | if(!isset($_POST[$field], $_POST[$field.'_confirmation'])){
106 | setFlash($field, "Os campos para atualizar a senha são obrigatórios");
107 | return false;
108 | }
109 |
110 | $value = strip_tags($_POST[$field]);
111 | $value_confirmation = strip_tags($_POST[$field.'_confirmation']);
112 |
113 | if($value !== $value_confirmation){
114 | setFlash($field, "Os dois campos tem que ser iguais");
115 | return false;
116 | }
117 |
118 | if($field === 'password'){
119 | return password_hash($value, PASSWORD_DEFAULT);
120 | }
121 | return $value;
122 | }
--------------------------------------------------------------------------------
/app/router/router.php:
--------------------------------------------------------------------------------
1 | $routes[$uri]] :
8 | [];
9 | }
10 |
11 | function regularExpressionMatchArrayRoutes($uri, $routes)
12 | {
13 | return array_filter(
14 | $routes,
15 | function ($value) use ($uri) {
16 | $regex = str_replace('/', '\/', ltrim($value, '/'));
17 | return preg_match("/^$regex$/", ltrim($uri, '/'));
18 | },
19 | ARRAY_FILTER_USE_KEY
20 | );
21 | }
22 |
23 | function params($uri, $matchedUri)
24 | {
25 | if (!empty($matchedUri)) {
26 | $matchedToGetParams = array_keys($matchedUri)[0];
27 | return array_diff(
28 | $uri,
29 | explode('/', ltrim($matchedToGetParams, '/'))
30 | );
31 | }
32 | return [];
33 | }
34 |
35 | function paramsFormat($uri, $params)
36 | {
37 | $paramsData = [];
38 | foreach ($params as $index => $param) {
39 | $paramsData[$uri[$index - 1]] = $param;
40 | }
41 |
42 | return $paramsData;
43 | }
44 |
45 |
46 | function router()
47 | {
48 | $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
49 |
50 | $routes = require 'routes.php';
51 | $requestMethod = $_SERVER['REQUEST_METHOD'];
52 |
53 | $matchedUri = exactMatchUriInArrayRoutes($uri, $routes[$requestMethod]);
54 |
55 | $params = [];
56 | if (empty($matchedUri)) {
57 | $matchedUri = regularExpressionMatchArrayRoutes($uri, $routes[$requestMethod]);
58 | $uri = explode('/', ltrim($uri, '/'));
59 | $params = params($uri, $matchedUri);
60 | $params = paramsFormat($uri, $params);
61 | }
62 |
63 | if ($_ENV['MAINTENANCE'] === 'true') {
64 | $matchedUri = ['/maintenance' => 'Maintenance@index'];
65 | }
66 |
67 | // dd($matchedUri);
68 |
69 |
70 | if (!empty($matchedUri)) {
71 | return controller($matchedUri, $params);
72 | }
73 |
74 |
75 | throw new Exception('Algo deu errado');
76 | }
77 |
--------------------------------------------------------------------------------
/app/router/routes.php:
--------------------------------------------------------------------------------
1 | [
5 | '/login' => 'Login@store',
6 | '/contact' => 'Contact@store',
7 | '/user/[0-9]+' => 'User@update',
8 | '/user/store' => 'User@store',
9 | '/user/image/update' => "UserImage@store",
10 | '/password/user/[0-9]+' => 'Password@update',
11 | ],
12 | 'GET' => [
13 | '/' => 'Home@index',
14 | '/users' => 'Users@index',
15 | '/contact' => 'Contact@index',
16 | '/user/create' => 'User@create',
17 | '/user/edit/profile' => 'User@edit',
18 | '/user/[0-9]+' => 'User@show',
19 | '/login' => 'Login@index',
20 | '/logout' => 'Login@destroy',
21 | ]
22 | ];
23 |
--------------------------------------------------------------------------------
/app/views/contact.php:
--------------------------------------------------------------------------------
1 | layout('master', ['title' => $title]) ?>
2 |
3 | Contato
4 |
5 |
6 |
7 |
8 |
25 |
--------------------------------------------------------------------------------
/app/views/create.php:
--------------------------------------------------------------------------------
1 | layout('master', ['title' => $title]) ?>
2 |
3 | Create
4 |
5 |
6 |
7 |
8 |
26 |
--------------------------------------------------------------------------------
/app/views/edit.php:
--------------------------------------------------------------------------------
1 | layout('master', ['title' => $title]) ?>
2 |
3 |
4 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
29 |
30 |
31 |
32 | path) : ?>
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
48 |
--------------------------------------------------------------------------------
/app/views/emails/contact.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
15 |
16 | Você recebeu uma mensagem de @fromName
17 |
18 | @message
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/views/emails/password.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Senha alterada
7 |
8 |
9 |
10 | Você recebeu uma mensagem de @fromName
11 |
12 | @message
13 |
14 | Caso não tenha sido você que tenha alterado a senha, entre em contato conosco.
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/views/home.php:
--------------------------------------------------------------------------------
1 | layout('master', ['title' => $title]) ?>
2 |
3 | Users count ?>
4 |
5 |
10 |
11 |
12 | rows as $user) : ?>
13 | - firstName; ?> | detalhes
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/views/login.php:
--------------------------------------------------------------------------------
1 | layout('master', ['title' => $title]) ?>
2 |
3 |
4 | Login
5 |
6 |
11 |
12 | Já está logado
13 |
--------------------------------------------------------------------------------
/app/views/maintenance.php:
--------------------------------------------------------------------------------
1 | layout('master', ['title' => $title]); ?>
2 |
3 |
4 | start('styles') ?>
5 |
6 | stop() ?>
7 |
8 | Em manutenção
--------------------------------------------------------------------------------
/app/views/master.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | e($title) ?>
7 |
8 |
9 | =$this->section('styles')?>
10 |
11 |
12 |
13 |
16 |
17 | =$this->section('content')?>
18 |
19 |
20 | =$this->section('scripts')?>
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/views/partials/header.php:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | Bem vindo,
11 |
12 | path) : ?>
13 |
->path ?>)
14 |
15 |
16 | firstName; ?> |
Logout |
17 |
Edit profile
18 |
19 | visitante
20 |
21 |
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alexandreeduardocardoso/php-pro",
3 | "description": "php-profissional",
4 | "authors": [
5 | {
6 | "name": "Alexandre Cardoso",
7 | "email": "alecar2007@gmail.com"
8 | }
9 | ],
10 | "require": {
11 | "symfony/var-dumper": "^5.3",
12 | "league/plates": "^3.4",
13 | "vlucas/phpdotenv": "^5.3",
14 | "doctrine/inflector": "^2.0",
15 | "phpmailer/phpmailer": "^6.5",
16 | "ext-pdo": "*"
17 | },
18 | "autoload": {
19 | "files": [
20 | "app/helpers/constants.php",
21 | "app/router/router.php",
22 | "app/core/controller.php",
23 | "app/database/connect.php",
24 | "app/database/queries.php",
25 | "app/helpers/redirect.php",
26 | "app/helpers/flash.php",
27 | "app/helpers/sessions.php",
28 | "app/helpers/validate.php",
29 | "app/helpers/validations.php",
30 | "app/helpers/helpers.php",
31 | "app/helpers/old.php",
32 | "app/helpers/csrf.php",
33 | "app/helpers/email.php",
34 | "app/helpers/image.php"
35 | ],
36 | "psr-4": {
37 | "app\\":"app"
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "ef43146c8b326a53a2dfb453f8a49114",
8 | "packages": [
9 | {
10 | "name": "doctrine/inflector",
11 | "version": "2.0.3",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/doctrine/inflector.git",
15 | "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/9cf661f4eb38f7c881cac67c75ea9b00bf97b210",
20 | "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": "^7.2 || ^8.0"
25 | },
26 | "require-dev": {
27 | "doctrine/coding-standard": "^7.0",
28 | "phpstan/phpstan": "^0.11",
29 | "phpstan/phpstan-phpunit": "^0.11",
30 | "phpstan/phpstan-strict-rules": "^0.11",
31 | "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
32 | },
33 | "type": "library",
34 | "extra": {
35 | "branch-alias": {
36 | "dev-master": "2.0.x-dev"
37 | }
38 | },
39 | "autoload": {
40 | "psr-4": {
41 | "Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
42 | }
43 | },
44 | "notification-url": "https://packagist.org/downloads/",
45 | "license": [
46 | "MIT"
47 | ],
48 | "authors": [
49 | {
50 | "name": "Guilherme Blanco",
51 | "email": "guilhermeblanco@gmail.com"
52 | },
53 | {
54 | "name": "Roman Borschel",
55 | "email": "roman@code-factory.org"
56 | },
57 | {
58 | "name": "Benjamin Eberlei",
59 | "email": "kontakt@beberlei.de"
60 | },
61 | {
62 | "name": "Jonathan Wage",
63 | "email": "jonwage@gmail.com"
64 | },
65 | {
66 | "name": "Johannes Schmitt",
67 | "email": "schmittjoh@gmail.com"
68 | }
69 | ],
70 | "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.",
71 | "homepage": "https://www.doctrine-project.org/projects/inflector.html",
72 | "keywords": [
73 | "inflection",
74 | "inflector",
75 | "lowercase",
76 | "manipulation",
77 | "php",
78 | "plural",
79 | "singular",
80 | "strings",
81 | "uppercase",
82 | "words"
83 | ],
84 | "support": {
85 | "issues": "https://github.com/doctrine/inflector/issues",
86 | "source": "https://github.com/doctrine/inflector/tree/2.0.x"
87 | },
88 | "funding": [
89 | {
90 | "url": "https://www.doctrine-project.org/sponsorship.html",
91 | "type": "custom"
92 | },
93 | {
94 | "url": "https://www.patreon.com/phpdoctrine",
95 | "type": "patreon"
96 | },
97 | {
98 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector",
99 | "type": "tidelift"
100 | }
101 | ],
102 | "time": "2020-05-29T15:13:26+00:00"
103 | },
104 | {
105 | "name": "graham-campbell/result-type",
106 | "version": "v1.0.2",
107 | "source": {
108 | "type": "git",
109 | "url": "https://github.com/GrahamCampbell/Result-Type.git",
110 | "reference": "84afea85c6841deeea872f36249a206e878a5de0"
111 | },
112 | "dist": {
113 | "type": "zip",
114 | "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/84afea85c6841deeea872f36249a206e878a5de0",
115 | "reference": "84afea85c6841deeea872f36249a206e878a5de0",
116 | "shasum": ""
117 | },
118 | "require": {
119 | "php": "^7.0 || ^8.0",
120 | "phpoption/phpoption": "^1.8"
121 | },
122 | "require-dev": {
123 | "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8"
124 | },
125 | "type": "library",
126 | "autoload": {
127 | "psr-4": {
128 | "GrahamCampbell\\ResultType\\": "src/"
129 | }
130 | },
131 | "notification-url": "https://packagist.org/downloads/",
132 | "license": [
133 | "MIT"
134 | ],
135 | "authors": [
136 | {
137 | "name": "Graham Campbell",
138 | "email": "hello@gjcampbell.co.uk"
139 | }
140 | ],
141 | "description": "An Implementation Of The Result Type",
142 | "keywords": [
143 | "Graham Campbell",
144 | "GrahamCampbell",
145 | "Result Type",
146 | "Result-Type",
147 | "result"
148 | ],
149 | "support": {
150 | "issues": "https://github.com/GrahamCampbell/Result-Type/issues",
151 | "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.2"
152 | },
153 | "funding": [
154 | {
155 | "url": "https://github.com/GrahamCampbell",
156 | "type": "github"
157 | },
158 | {
159 | "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
160 | "type": "tidelift"
161 | }
162 | ],
163 | "time": "2021-08-28T21:34:50+00:00"
164 | },
165 | {
166 | "name": "league/plates",
167 | "version": "v3.4.0",
168 | "source": {
169 | "type": "git",
170 | "url": "https://github.com/thephpleague/plates.git",
171 | "reference": "6d3ee31199b536a4e003b34a356ca20f6f75496a"
172 | },
173 | "dist": {
174 | "type": "zip",
175 | "url": "https://api.github.com/repos/thephpleague/plates/zipball/6d3ee31199b536a4e003b34a356ca20f6f75496a",
176 | "reference": "6d3ee31199b536a4e003b34a356ca20f6f75496a",
177 | "shasum": ""
178 | },
179 | "require": {
180 | "php": "^7.0|^8.0"
181 | },
182 | "require-dev": {
183 | "mikey179/vfsstream": "^1.6",
184 | "phpunit/phpunit": "^9.5",
185 | "squizlabs/php_codesniffer": "^3.5"
186 | },
187 | "type": "library",
188 | "extra": {
189 | "branch-alias": {
190 | "dev-master": "3.0-dev"
191 | }
192 | },
193 | "autoload": {
194 | "psr-4": {
195 | "League\\Plates\\": "src"
196 | }
197 | },
198 | "notification-url": "https://packagist.org/downloads/",
199 | "license": [
200 | "MIT"
201 | ],
202 | "authors": [
203 | {
204 | "name": "Jonathan Reinink",
205 | "email": "jonathan@reinink.ca",
206 | "role": "Developer"
207 | },
208 | {
209 | "name": "RJ Garcia",
210 | "email": "ragboyjr@icloud.com",
211 | "role": "Developer"
212 | }
213 | ],
214 | "description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
215 | "homepage": "https://platesphp.com",
216 | "keywords": [
217 | "league",
218 | "package",
219 | "templates",
220 | "templating",
221 | "views"
222 | ],
223 | "support": {
224 | "issues": "https://github.com/thephpleague/plates/issues",
225 | "source": "https://github.com/thephpleague/plates/tree/v3.4.0"
226 | },
227 | "time": "2020-12-25T05:00:37+00:00"
228 | },
229 | {
230 | "name": "phpmailer/phpmailer",
231 | "version": "v6.5.1",
232 | "source": {
233 | "type": "git",
234 | "url": "https://github.com/PHPMailer/PHPMailer.git",
235 | "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355"
236 | },
237 | "dist": {
238 | "type": "zip",
239 | "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/dd803df5ad7492e1b40637f7ebd258fee5ca7355",
240 | "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355",
241 | "shasum": ""
242 | },
243 | "require": {
244 | "ext-ctype": "*",
245 | "ext-filter": "*",
246 | "ext-hash": "*",
247 | "php": ">=5.5.0"
248 | },
249 | "require-dev": {
250 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
251 | "doctrine/annotations": "^1.2",
252 | "php-parallel-lint/php-console-highlighter": "^0.5.0",
253 | "php-parallel-lint/php-parallel-lint": "^1.3",
254 | "phpcompatibility/php-compatibility": "^9.3.5",
255 | "roave/security-advisories": "dev-latest",
256 | "squizlabs/php_codesniffer": "^3.6.0",
257 | "yoast/phpunit-polyfills": "^1.0.0"
258 | },
259 | "suggest": {
260 | "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
261 | "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
262 | "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
263 | "psr/log": "For optional PSR-3 debug logging",
264 | "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
265 | "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
266 | },
267 | "type": "library",
268 | "autoload": {
269 | "psr-4": {
270 | "PHPMailer\\PHPMailer\\": "src/"
271 | }
272 | },
273 | "notification-url": "https://packagist.org/downloads/",
274 | "license": [
275 | "LGPL-2.1-only"
276 | ],
277 | "authors": [
278 | {
279 | "name": "Marcus Bointon",
280 | "email": "phpmailer@synchromedia.co.uk"
281 | },
282 | {
283 | "name": "Jim Jagielski",
284 | "email": "jimjag@gmail.com"
285 | },
286 | {
287 | "name": "Andy Prevost",
288 | "email": "codeworxtech@users.sourceforge.net"
289 | },
290 | {
291 | "name": "Brent R. Matzelle"
292 | }
293 | ],
294 | "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
295 | "support": {
296 | "issues": "https://github.com/PHPMailer/PHPMailer/issues",
297 | "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.1"
298 | },
299 | "funding": [
300 | {
301 | "url": "https://github.com/Synchro",
302 | "type": "github"
303 | }
304 | ],
305 | "time": "2021-08-18T09:14:16+00:00"
306 | },
307 | {
308 | "name": "phpoption/phpoption",
309 | "version": "1.8.0",
310 | "source": {
311 | "type": "git",
312 | "url": "https://github.com/schmittjoh/php-option.git",
313 | "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28"
314 | },
315 | "dist": {
316 | "type": "zip",
317 | "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5455cb38aed4523f99977c4a12ef19da4bfe2a28",
318 | "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28",
319 | "shasum": ""
320 | },
321 | "require": {
322 | "php": "^7.0 || ^8.0"
323 | },
324 | "require-dev": {
325 | "bamarni/composer-bin-plugin": "^1.4.1",
326 | "phpunit/phpunit": "^6.5.14 || ^7.0.20 || ^8.5.19 || ^9.5.8"
327 | },
328 | "type": "library",
329 | "extra": {
330 | "branch-alias": {
331 | "dev-master": "1.8-dev"
332 | }
333 | },
334 | "autoload": {
335 | "psr-4": {
336 | "PhpOption\\": "src/PhpOption/"
337 | }
338 | },
339 | "notification-url": "https://packagist.org/downloads/",
340 | "license": [
341 | "Apache-2.0"
342 | ],
343 | "authors": [
344 | {
345 | "name": "Johannes M. Schmitt",
346 | "email": "schmittjoh@gmail.com"
347 | },
348 | {
349 | "name": "Graham Campbell",
350 | "email": "hello@gjcampbell.co.uk"
351 | }
352 | ],
353 | "description": "Option Type for PHP",
354 | "keywords": [
355 | "language",
356 | "option",
357 | "php",
358 | "type"
359 | ],
360 | "support": {
361 | "issues": "https://github.com/schmittjoh/php-option/issues",
362 | "source": "https://github.com/schmittjoh/php-option/tree/1.8.0"
363 | },
364 | "funding": [
365 | {
366 | "url": "https://github.com/GrahamCampbell",
367 | "type": "github"
368 | },
369 | {
370 | "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
371 | "type": "tidelift"
372 | }
373 | ],
374 | "time": "2021-08-28T21:27:29+00:00"
375 | },
376 | {
377 | "name": "symfony/polyfill-ctype",
378 | "version": "v1.23.0",
379 | "source": {
380 | "type": "git",
381 | "url": "https://github.com/symfony/polyfill-ctype.git",
382 | "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
383 | },
384 | "dist": {
385 | "type": "zip",
386 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
387 | "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
388 | "shasum": ""
389 | },
390 | "require": {
391 | "php": ">=7.1"
392 | },
393 | "suggest": {
394 | "ext-ctype": "For best performance"
395 | },
396 | "type": "library",
397 | "extra": {
398 | "branch-alias": {
399 | "dev-main": "1.23-dev"
400 | },
401 | "thanks": {
402 | "name": "symfony/polyfill",
403 | "url": "https://github.com/symfony/polyfill"
404 | }
405 | },
406 | "autoload": {
407 | "psr-4": {
408 | "Symfony\\Polyfill\\Ctype\\": ""
409 | },
410 | "files": [
411 | "bootstrap.php"
412 | ]
413 | },
414 | "notification-url": "https://packagist.org/downloads/",
415 | "license": [
416 | "MIT"
417 | ],
418 | "authors": [
419 | {
420 | "name": "Gert de Pagter",
421 | "email": "BackEndTea@gmail.com"
422 | },
423 | {
424 | "name": "Symfony Community",
425 | "homepage": "https://symfony.com/contributors"
426 | }
427 | ],
428 | "description": "Symfony polyfill for ctype functions",
429 | "homepage": "https://symfony.com",
430 | "keywords": [
431 | "compatibility",
432 | "ctype",
433 | "polyfill",
434 | "portable"
435 | ],
436 | "support": {
437 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
438 | },
439 | "funding": [
440 | {
441 | "url": "https://symfony.com/sponsor",
442 | "type": "custom"
443 | },
444 | {
445 | "url": "https://github.com/fabpot",
446 | "type": "github"
447 | },
448 | {
449 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
450 | "type": "tidelift"
451 | }
452 | ],
453 | "time": "2021-02-19T12:13:01+00:00"
454 | },
455 | {
456 | "name": "symfony/polyfill-mbstring",
457 | "version": "v1.23.1",
458 | "source": {
459 | "type": "git",
460 | "url": "https://github.com/symfony/polyfill-mbstring.git",
461 | "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
462 | },
463 | "dist": {
464 | "type": "zip",
465 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
466 | "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
467 | "shasum": ""
468 | },
469 | "require": {
470 | "php": ">=7.1"
471 | },
472 | "suggest": {
473 | "ext-mbstring": "For best performance"
474 | },
475 | "type": "library",
476 | "extra": {
477 | "branch-alias": {
478 | "dev-main": "1.23-dev"
479 | },
480 | "thanks": {
481 | "name": "symfony/polyfill",
482 | "url": "https://github.com/symfony/polyfill"
483 | }
484 | },
485 | "autoload": {
486 | "psr-4": {
487 | "Symfony\\Polyfill\\Mbstring\\": ""
488 | },
489 | "files": [
490 | "bootstrap.php"
491 | ]
492 | },
493 | "notification-url": "https://packagist.org/downloads/",
494 | "license": [
495 | "MIT"
496 | ],
497 | "authors": [
498 | {
499 | "name": "Nicolas Grekas",
500 | "email": "p@tchwork.com"
501 | },
502 | {
503 | "name": "Symfony Community",
504 | "homepage": "https://symfony.com/contributors"
505 | }
506 | ],
507 | "description": "Symfony polyfill for the Mbstring extension",
508 | "homepage": "https://symfony.com",
509 | "keywords": [
510 | "compatibility",
511 | "mbstring",
512 | "polyfill",
513 | "portable",
514 | "shim"
515 | ],
516 | "support": {
517 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
518 | },
519 | "funding": [
520 | {
521 | "url": "https://symfony.com/sponsor",
522 | "type": "custom"
523 | },
524 | {
525 | "url": "https://github.com/fabpot",
526 | "type": "github"
527 | },
528 | {
529 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
530 | "type": "tidelift"
531 | }
532 | ],
533 | "time": "2021-05-27T12:26:48+00:00"
534 | },
535 | {
536 | "name": "symfony/polyfill-php80",
537 | "version": "v1.23.1",
538 | "source": {
539 | "type": "git",
540 | "url": "https://github.com/symfony/polyfill-php80.git",
541 | "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
542 | },
543 | "dist": {
544 | "type": "zip",
545 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
546 | "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
547 | "shasum": ""
548 | },
549 | "require": {
550 | "php": ">=7.1"
551 | },
552 | "type": "library",
553 | "extra": {
554 | "branch-alias": {
555 | "dev-main": "1.23-dev"
556 | },
557 | "thanks": {
558 | "name": "symfony/polyfill",
559 | "url": "https://github.com/symfony/polyfill"
560 | }
561 | },
562 | "autoload": {
563 | "psr-4": {
564 | "Symfony\\Polyfill\\Php80\\": ""
565 | },
566 | "files": [
567 | "bootstrap.php"
568 | ],
569 | "classmap": [
570 | "Resources/stubs"
571 | ]
572 | },
573 | "notification-url": "https://packagist.org/downloads/",
574 | "license": [
575 | "MIT"
576 | ],
577 | "authors": [
578 | {
579 | "name": "Ion Bazan",
580 | "email": "ion.bazan@gmail.com"
581 | },
582 | {
583 | "name": "Nicolas Grekas",
584 | "email": "p@tchwork.com"
585 | },
586 | {
587 | "name": "Symfony Community",
588 | "homepage": "https://symfony.com/contributors"
589 | }
590 | ],
591 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
592 | "homepage": "https://symfony.com",
593 | "keywords": [
594 | "compatibility",
595 | "polyfill",
596 | "portable",
597 | "shim"
598 | ],
599 | "support": {
600 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
601 | },
602 | "funding": [
603 | {
604 | "url": "https://symfony.com/sponsor",
605 | "type": "custom"
606 | },
607 | {
608 | "url": "https://github.com/fabpot",
609 | "type": "github"
610 | },
611 | {
612 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
613 | "type": "tidelift"
614 | }
615 | ],
616 | "time": "2021-07-28T13:41:28+00:00"
617 | },
618 | {
619 | "name": "symfony/var-dumper",
620 | "version": "v5.3.7",
621 | "source": {
622 | "type": "git",
623 | "url": "https://github.com/symfony/var-dumper.git",
624 | "reference": "3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f"
625 | },
626 | "dist": {
627 | "type": "zip",
628 | "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f",
629 | "reference": "3ad5af4aed07d0a0201bbcfc42658fe6c5b2fb8f",
630 | "shasum": ""
631 | },
632 | "require": {
633 | "php": ">=7.2.5",
634 | "symfony/polyfill-mbstring": "~1.0",
635 | "symfony/polyfill-php80": "^1.16"
636 | },
637 | "conflict": {
638 | "phpunit/phpunit": "<5.4.3",
639 | "symfony/console": "<4.4"
640 | },
641 | "require-dev": {
642 | "ext-iconv": "*",
643 | "symfony/console": "^4.4|^5.0",
644 | "symfony/process": "^4.4|^5.0",
645 | "twig/twig": "^2.13|^3.0.4"
646 | },
647 | "suggest": {
648 | "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
649 | "ext-intl": "To show region name in time zone dump",
650 | "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
651 | },
652 | "bin": [
653 | "Resources/bin/var-dump-server"
654 | ],
655 | "type": "library",
656 | "autoload": {
657 | "files": [
658 | "Resources/functions/dump.php"
659 | ],
660 | "psr-4": {
661 | "Symfony\\Component\\VarDumper\\": ""
662 | },
663 | "exclude-from-classmap": [
664 | "/Tests/"
665 | ]
666 | },
667 | "notification-url": "https://packagist.org/downloads/",
668 | "license": [
669 | "MIT"
670 | ],
671 | "authors": [
672 | {
673 | "name": "Nicolas Grekas",
674 | "email": "p@tchwork.com"
675 | },
676 | {
677 | "name": "Symfony Community",
678 | "homepage": "https://symfony.com/contributors"
679 | }
680 | ],
681 | "description": "Provides mechanisms for walking through any arbitrary PHP variable",
682 | "homepage": "https://symfony.com",
683 | "keywords": [
684 | "debug",
685 | "dump"
686 | ],
687 | "support": {
688 | "source": "https://github.com/symfony/var-dumper/tree/v5.3.7"
689 | },
690 | "funding": [
691 | {
692 | "url": "https://symfony.com/sponsor",
693 | "type": "custom"
694 | },
695 | {
696 | "url": "https://github.com/fabpot",
697 | "type": "github"
698 | },
699 | {
700 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
701 | "type": "tidelift"
702 | }
703 | ],
704 | "time": "2021-08-04T23:19:25+00:00"
705 | },
706 | {
707 | "name": "vlucas/phpdotenv",
708 | "version": "v5.3.0",
709 | "source": {
710 | "type": "git",
711 | "url": "https://github.com/vlucas/phpdotenv.git",
712 | "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56"
713 | },
714 | "dist": {
715 | "type": "zip",
716 | "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b3eac5c7ac896e52deab4a99068e3f4ab12d9e56",
717 | "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56",
718 | "shasum": ""
719 | },
720 | "require": {
721 | "ext-pcre": "*",
722 | "graham-campbell/result-type": "^1.0.1",
723 | "php": "^7.1.3 || ^8.0",
724 | "phpoption/phpoption": "^1.7.4",
725 | "symfony/polyfill-ctype": "^1.17",
726 | "symfony/polyfill-mbstring": "^1.17",
727 | "symfony/polyfill-php80": "^1.17"
728 | },
729 | "require-dev": {
730 | "bamarni/composer-bin-plugin": "^1.4.1",
731 | "ext-filter": "*",
732 | "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5.1"
733 | },
734 | "suggest": {
735 | "ext-filter": "Required to use the boolean validator."
736 | },
737 | "type": "library",
738 | "extra": {
739 | "branch-alias": {
740 | "dev-master": "5.3-dev"
741 | }
742 | },
743 | "autoload": {
744 | "psr-4": {
745 | "Dotenv\\": "src/"
746 | }
747 | },
748 | "notification-url": "https://packagist.org/downloads/",
749 | "license": [
750 | "BSD-3-Clause"
751 | ],
752 | "authors": [
753 | {
754 | "name": "Graham Campbell",
755 | "email": "graham@alt-three.com",
756 | "homepage": "https://gjcampbell.co.uk/"
757 | },
758 | {
759 | "name": "Vance Lucas",
760 | "email": "vance@vancelucas.com",
761 | "homepage": "https://vancelucas.com/"
762 | }
763 | ],
764 | "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
765 | "keywords": [
766 | "dotenv",
767 | "env",
768 | "environment"
769 | ],
770 | "support": {
771 | "issues": "https://github.com/vlucas/phpdotenv/issues",
772 | "source": "https://github.com/vlucas/phpdotenv/tree/v5.3.0"
773 | },
774 | "funding": [
775 | {
776 | "url": "https://github.com/GrahamCampbell",
777 | "type": "github"
778 | },
779 | {
780 | "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
781 | "type": "tidelift"
782 | }
783 | ],
784 | "time": "2021-01-20T15:23:13+00:00"
785 | }
786 | ],
787 | "packages-dev": [],
788 | "aliases": [],
789 | "minimum-stability": "stable",
790 | "stability-flags": [],
791 | "prefer-stable": false,
792 | "prefer-lowest": false,
793 | "platform": [],
794 | "platform-dev": [],
795 | "plugin-api-version": "2.1.0"
796 | }
797 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "php-pro",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "webpack.config.js",
6 | "scripts": {
7 | "dev": "NODE_ENV=development webpack --progress --watch",
8 | "prod": "NODE_ENV=production webpack --progress --watch"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/aleduca/php-profissional.git"
13 | },
14 | "keywords": [],
15 | "author": "",
16 | "license": "ISC",
17 | "bugs": {
18 | "url": "https://github.com/aleduca/php-profissional/issues"
19 | },
20 | "devDependencies": {
21 | "@babel/cli": "^7.10.5",
22 | "@babel/core": "^7.11.1",
23 | "@babel/polyfill": "^7.12.1",
24 | "@babel/preset-env": "^7.11.0",
25 | "babel-loader": "^8.1.0",
26 | "eslint": "^7.7.0",
27 | "webpack": "^4.44.1",
28 | "webpack-cli": "^3.3.12"
29 | },
30 | "dependencies": {
31 | "alpinejs": "^3.3.3",
32 | "axios": "^0.21.4"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aleduca/php-profissional/3504041e7b8eb58e0ad1ed88e83636fbbff99768/public/.DS_Store
--------------------------------------------------------------------------------
/public/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aleduca/php-profissional/3504041e7b8eb58e0ad1ed88e83636fbbff99768/public/assets/.DS_Store
--------------------------------------------------------------------------------
/public/assets/css/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=PT+Sans:wght@400;700&display=swap');
2 |
3 | html,
4 | body {
5 | font-family: 'PT Sans', sans-serif;
6 | }
7 |
8 | .container {
9 | margin: auto;
10 | width: 50%;
11 | border: 3px solid green;
12 | padding: 10px;
13 | }
14 |
15 | #box-login {
16 | margin: 0 auto;
17 | background: tomato;
18 | padding: 5px;
19 | width: 400px;
20 | color: white;
21 | text-align: center;
22 | }
23 |
24 | .button-green {
25 | background-color: green;
26 | border: none;
27 | color: white;
28 | }
29 |
30 | #header {
31 | display: flex;
32 | justify-content: space-between;
33 | width: 100%;
34 | align-items: center;
35 | }
36 |
37 | ul#menu_list {
38 | list-style: none;
39 | display: flex;
40 | padding: 0;
41 | justify-content: space-between;
42 | }
43 |
44 | ul#menu_list li {
45 | margin-right: 15px;
46 | }
47 |
48 | #status_login {
49 | background-color: #efefef;
50 | }
51 |
52 | ul#users-home {
53 | list-style: none;
54 | padding: 0;
55 | }
56 |
57 | ul#users-home li {
58 | background-color: aquamarine;
59 | padding: 5px;
60 | margin-bottom: 3px;
61 | }
62 |
--------------------------------------------------------------------------------
/public/assets/js/alpine-components/users.js:
--------------------------------------------------------------------------------
1 | import http from "../http";
2 |
3 | function users() {
4 | return {
5 | data: [],
6 | async loadUsers() {
7 | try {
8 | const { data } = await http.get("/users");
9 | this.data = data;
10 | } catch (error) {
11 | console.log(error);
12 | }
13 | },
14 | };
15 | }
16 |
17 | export default users;
18 |
--------------------------------------------------------------------------------
/public/assets/js/app.js:
--------------------------------------------------------------------------------
1 | import Alpine from "alpinejs";
2 | import users from "./alpine-components/users";
3 |
4 | window.Alpine = Alpine;
5 | window.users = users;
6 |
7 | Alpine.start();
8 |
--------------------------------------------------------------------------------
/public/assets/js/http.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | const axiosConfig = axios.create({
4 | headers: {
5 | 'Content-type': 'application/json',
6 | HTTP_X_REQUESTED_WITH: 'XMLHttpRequest',
7 | },
8 | baseURL: 'http://localhost:8000',
9 | });
10 |
11 | export default axiosConfig;
12 |
--------------------------------------------------------------------------------
/public/assets/js/teste.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aleduca/php-profissional/3504041e7b8eb58e0ad1ed88e83636fbbff99768/public/assets/js/teste.js
--------------------------------------------------------------------------------
/public/assets/js/users.js:
--------------------------------------------------------------------------------
1 | import http from './http';
2 |
3 | async function users() {
4 | try {
5 | const { data } = await http.get('/users');
6 | console.log(data);
7 | } catch (error) {
8 | console.log(error);
9 | }
10 | }
11 |
12 | export default users;
13 |
--------------------------------------------------------------------------------
/public/bootstrap.php:
--------------------------------------------------------------------------------
1 | load();
8 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | render($data['view'], $data['data']);
39 |
40 | // extract($data['data']);
41 |
42 | // $view = $data['view'];
43 |
44 | // require VIEWS.'master.php';
45 | } catch (Exception $e) {
46 | var_dump($e->getMessage());
47 | }
48 |
--------------------------------------------------------------------------------
/public/maintenance.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Em manutenção
8 |
9 |
10 | Site em manutenção
11 |
12 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: process.env.NODE_ENV,
5 | devtool: process.env.NODE_ENV == 'development' ? 'source-map' : '',
6 | entry: {
7 | app: ['@babel/polyfill', './public/assets/js/app.js'],
8 | },
9 | output: {
10 | path: path.resolve(__dirname, 'public'),
11 | filename: '[name].js',
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.js$/,
17 | exclude: /node_modules/,
18 | loader: 'babel-loader',
19 | },
20 | ],
21 | },
22 | };
23 |
--------------------------------------------------------------------------------