Compare commits
	
		
			74 Commits
		
	
	
		
			e1d1ef5eeb
			...
			mikro24
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b8e5730ec0 | |||
| b6fd7876d3 | |||
| 1dc31bcb1b | |||
| 3ff406d053 | |||
| 6abe519a44 | |||
| c6c88456cf | |||
| 5a805aba07 | |||
| 1541d05715 | |||
| dc78e203ea | |||
| 17a90358a7 | |||
| 0266a89ae3 | |||
| 56a3e584e7 | |||
| e2bf38299b | |||
| 24c8a3d9d7 | |||
| dba37e57f9 | |||
| c68cf1643e | |||
| affe02ec04 | |||
| b678720ebd | |||
| 14f9f247bc | |||
| 65a87acc48 | |||
| e04cf94edd | |||
| 9ee8ae39df | |||
| 70aa4d1f06 | |||
| 2f99531780 | |||
| 60860a0bce | |||
| bb3d0f6e1b | |||
| 7ee8e8860e | |||
| 32dcab7592 | |||
| 88cf11d45d | |||
| 6c203a0213 | |||
| 9867df0a04 | |||
| 0fba7bc0a0 | |||
| f46e73c647 | |||
| 1a8b31b3a2 | |||
| a832a3c60b | |||
| 904fd798f6 | |||
| 4ed3dcd603 | |||
| 8bc252ba4d | |||
| 78f25fdfd3 | |||
| e2da6000b3 | |||
| 32133a0d05 | |||
| 572cc1eb89 | |||
| 48585f14ab | |||
| 47439fe358 | |||
| 8e0a2ff6e8 | |||
| ce798e3b65 | |||
| 21fd674dd0 | |||
| 8864875699 | |||
| fe0a3c212d | |||
| d2f5427df1 | |||
| 5ed539a471 | |||
| 5bc0b7966b | |||
| d0e1d2e87d | |||
| 1b794f775d | |||
| 744117d958 | |||
| cce18f6516 | |||
| a973a4362f | |||
| 3bf0c2b44f | |||
| ec022d09e4 | |||
| 148eff1557 | |||
| ab4a00d25c | |||
| 753b832cbc | |||
| e5f4656d71 | |||
| 117903ac7c | |||
| 4665e1706f | |||
| 8189abfd29 | |||
| 72503d7fe2 | |||
| 3f4653b81f | |||
| 0ed667d594 | |||
| fddc58fb14 | |||
| ad63a40a0d | |||
| e13bbee1e6 | |||
| c6af0d1b1c | |||
| fd368d895d | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
/config.json
 | 
			
		||||
							
								
								
									
										23
									
								
								CakePHP/.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								CakePHP/.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
This is a (multiple allowed):
 | 
			
		||||
 | 
			
		||||
* [x] bug
 | 
			
		||||
* [ ] enhancement
 | 
			
		||||
* [ ] feature-discussion (RFC)
 | 
			
		||||
 | 
			
		||||
* CakePHP Application Skeleton Version: EXACT RELEASE VERSION OR COMMIT HASH, HERE.
 | 
			
		||||
* Platform and Target: YOUR WEB-SERVER, DATABASE AND OTHER RELEVANT INFO AND HOW THE REQUEST IS BEING MADE, HERE.
 | 
			
		||||
 | 
			
		||||
### What you did
 | 
			
		||||
EXPLAIN WHAT YOU DID, PREFERABLY WITH CODE EXAMPLES, HERE.
 | 
			
		||||
 | 
			
		||||
### What happened
 | 
			
		||||
EXPLAIN WHAT IS ACTUALLY HAPPENING, HERE.
 | 
			
		||||
 | 
			
		||||
### What you expected to happen
 | 
			
		||||
EXPLAIN WHAT IS TO BE EXPECTED, HERE.
 | 
			
		||||
 | 
			
		||||
P.S. Remember, an issue is not the place to ask questions. You can use [Stack Overflow](https://stackoverflow.com/questions/tagged/cakephp)
 | 
			
		||||
for that or join the #cakephp channel on irc.freenode.net, where we will be more
 | 
			
		||||
than happy to help answer your questions.
 | 
			
		||||
 | 
			
		||||
Before you open an issue, please check if a similar issue already exists or has been closed before.
 | 
			
		||||
							
								
								
									
										14
									
								
								CakePHP/.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								CakePHP/.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
<!---
 | 
			
		||||
 | 
			
		||||
**PLEASE NOTE:**
 | 
			
		||||
 | 
			
		||||
This is only a issue tracker for issues related to the CakePHP Application Skeleton.
 | 
			
		||||
For CakePHP Framework issues please use this [issue tracker](https://github.com/cakephp/cakephp/issues).
 | 
			
		||||
 | 
			
		||||
Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
 | 
			
		||||
 | 
			
		||||
The best way to propose a feature is to open an issue first and discuss your ideas there before implementing them.
 | 
			
		||||
 | 
			
		||||
Always follow the [contribution guidelines](https://github.com/cakephp/cakephp/blob/master/.github/CONTRIBUTING.md) guidelines when submitting a pull request. In particular, make sure existing tests still pass, and add tests for all new behavior. When fixing a bug, you may want to add a test to verify the fix.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
							
								
								
									
										12
									
								
								CakePHP/.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								CakePHP/.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
version: 2
 | 
			
		||||
updates:
 | 
			
		||||
- package-ecosystem: composer
 | 
			
		||||
  directory: "/"
 | 
			
		||||
  schedule:
 | 
			
		||||
    interval: weekly
 | 
			
		||||
  open-pull-requests-limit: 10
 | 
			
		||||
- package-ecosystem: github-actions
 | 
			
		||||
  directory: "/"
 | 
			
		||||
  schedule:
 | 
			
		||||
    interval: weekly
 | 
			
		||||
  open-pull-requests-limit: 10
 | 
			
		||||
							
								
								
									
										89
									
								
								CakePHP/.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								CakePHP/.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
name: CI
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '4.x'
 | 
			
		||||
      - '4.next'
 | 
			
		||||
      - '5.x'
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches:
 | 
			
		||||
      - '*'
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: read
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  testsuite:
 | 
			
		||||
    runs-on: ubuntu-18.04
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        php-version: ['7.4', '8.0', '8.1']
 | 
			
		||||
    name: PHP ${{ matrix.php-version }}
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
    - name: Setup PHP
 | 
			
		||||
      uses: shivammathur/setup-php@v2
 | 
			
		||||
      with:
 | 
			
		||||
        php-version: ${{ matrix.php-version }}
 | 
			
		||||
        extensions: mbstring, intl, pdo_sqlite
 | 
			
		||||
        coverage: none
 | 
			
		||||
 | 
			
		||||
    - name: Composer install
 | 
			
		||||
      run: |
 | 
			
		||||
        if [[ ${{ matrix.php-version }} == '8.1' ]]; then
 | 
			
		||||
          composer update --ignore-platform-reqs
 | 
			
		||||
        else
 | 
			
		||||
          composer update
 | 
			
		||||
        fi
 | 
			
		||||
        composer run-script post-install-cmd --no-interaction
 | 
			
		||||
 | 
			
		||||
    - name: Run PHPUnit
 | 
			
		||||
      run: |
 | 
			
		||||
        cp config/app_local.example.php config/app_local.php
 | 
			
		||||
        vendor/bin/phpunit
 | 
			
		||||
      env:
 | 
			
		||||
        DATABASE_TEST_URL: sqlite://./testdb.sqlite
 | 
			
		||||
 | 
			
		||||
  coding-standard:
 | 
			
		||||
    name: Coding Standard
 | 
			
		||||
    runs-on: ubuntu-18.04
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
    - name: Setup PHP
 | 
			
		||||
      uses: shivammathur/setup-php@v2
 | 
			
		||||
      with:
 | 
			
		||||
        php-version: '7.4'
 | 
			
		||||
        extensions: mbstring, intl
 | 
			
		||||
        coverage: none
 | 
			
		||||
 | 
			
		||||
    - name: Composer install
 | 
			
		||||
      run: composer install
 | 
			
		||||
 | 
			
		||||
    - name: Run PHP CodeSniffer
 | 
			
		||||
      run: composer cs-check
 | 
			
		||||
 | 
			
		||||
  static-analysis:
 | 
			
		||||
    name: Static Analysis
 | 
			
		||||
    runs-on: ubuntu-18.04
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
    - name: Setup PHP
 | 
			
		||||
      uses: shivammathur/setup-php@v2
 | 
			
		||||
      with:
 | 
			
		||||
        php-version: '7.4'
 | 
			
		||||
        extensions: mbstring, intl
 | 
			
		||||
        coverage: none
 | 
			
		||||
 | 
			
		||||
    - name: Composer install
 | 
			
		||||
      run: composer require --dev phpstan/phpstan:^1.0.0
 | 
			
		||||
 | 
			
		||||
    - name: Run phpstan
 | 
			
		||||
      run: vendor/bin/phpstan
 | 
			
		||||
							
								
								
									
										29
									
								
								CakePHP/.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								CakePHP/.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
name: Mark stale issues and pull requests
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  schedule:
 | 
			
		||||
  - cron: "0 0 * * *"
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: read
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  stale:
 | 
			
		||||
 | 
			
		||||
    permissions:
 | 
			
		||||
      issues: write  # for actions/stale to close stale issues
 | 
			
		||||
      pull-requests: write  # for actions/stale to close stale PRs
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/stale@v5
 | 
			
		||||
      with:
 | 
			
		||||
        repo-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
        stale-issue-message: 'This issue is stale because it has been open for 120 days with no activity. Remove the `stale` label or comment or this will be closed in 15 days'
 | 
			
		||||
        stale-pr-message: 'This pull request is stale because it has been open 30 days with no activity. Remove the `stale` label or comment on this issue, or it will be closed in 15 days'
 | 
			
		||||
        stale-issue-label: 'stale'
 | 
			
		||||
        stale-pr-label: 'stale'
 | 
			
		||||
        days-before-stale: 120
 | 
			
		||||
        days-before-close: 15
 | 
			
		||||
        exempt-issue-labels: 'pinned'
 | 
			
		||||
        exempt-pr-labels: 'pinned'
 | 
			
		||||
							
								
								
									
										47
									
								
								CakePHP/bin/bash_completion.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								CakePHP/bin/bash_completion.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
#
 | 
			
		||||
# Bash completion file for CakePHP console.
 | 
			
		||||
# Copy this file to a file named `cake` under `/etc/bash_completion.d/`.
 | 
			
		||||
# For more info check https://book.cakephp.org/4/en/console-commands/completion.html#how-to-enable-bash-autocompletion-for-the-cakephp-console
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
_cake()
 | 
			
		||||
{
 | 
			
		||||
    local cur prev opts cake
 | 
			
		||||
    COMPREPLY=()
 | 
			
		||||
    cake="${COMP_WORDS[0]}"
 | 
			
		||||
    cur="${COMP_WORDS[COMP_CWORD]}"
 | 
			
		||||
    prev="${COMP_WORDS[COMP_CWORD-1]}"
 | 
			
		||||
 | 
			
		||||
    if [[ "$cur" == -* ]] ; then
 | 
			
		||||
        if [[ ${COMP_CWORD} = 1 ]] ; then
 | 
			
		||||
            opts=$(${cake} completion options)
 | 
			
		||||
        elif [[ ${COMP_CWORD} = 2 ]] ; then
 | 
			
		||||
            opts=$(${cake} completion options "${COMP_WORDS[1]}")
 | 
			
		||||
        else
 | 
			
		||||
            opts=$(${cake} completion options "${COMP_WORDS[1]}" "${COMP_WORDS[2]}")
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
 | 
			
		||||
        return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ ${COMP_CWORD} = 1 ]] ; then
 | 
			
		||||
        opts=$(${cake} completion commands)
 | 
			
		||||
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
 | 
			
		||||
        return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ ${COMP_CWORD} = 2 ]] ; then
 | 
			
		||||
        opts=$(${cake} completion subcommands $prev)
 | 
			
		||||
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
 | 
			
		||||
        if [[ $COMPREPLY = "" ]] ; then
 | 
			
		||||
            _filedir
 | 
			
		||||
            return 0
 | 
			
		||||
        fi
 | 
			
		||||
        return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
complete -F _cake cake bin/cake
 | 
			
		||||
							
								
								
									
										5790
									
								
								CakePHP/composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5790
									
								
								CakePHP/composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										6
									
								
								CakePHP/phpcs.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								CakePHP/phpcs.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
<ruleset name="App">
 | 
			
		||||
    <config name="installed_paths" value="../../cakephp/cakephp-codesniffer"/>
 | 
			
		||||
 | 
			
		||||
    <rule ref="CakePHP"/>
 | 
			
		||||
</ruleset>
 | 
			
		||||
							
								
								
									
										8
									
								
								CakePHP/phpstan.neon
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								CakePHP/phpstan.neon
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
parameters:
 | 
			
		||||
    level: 8
 | 
			
		||||
    checkMissingIterableValueType: false
 | 
			
		||||
    treatPhpDocTypesAsCertain: false
 | 
			
		||||
    paths:
 | 
			
		||||
        - src/
 | 
			
		||||
    excludePaths:
 | 
			
		||||
        - src/Console/Installer.php
 | 
			
		||||
							
								
								
									
										105
									
								
								CakePHP/src/Controller/AddressesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								CakePHP/src/Controller/AddressesController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Addresses Controller
 | 
			
		||||
 *
 | 
			
		||||
 * @property \App\Model\Table\AddressesTable $Addresses
 | 
			
		||||
 * @method \App\Model\Entity\Address[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
 | 
			
		||||
 */
 | 
			
		||||
class AddressesController extends AppController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Index method
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Renders view
 | 
			
		||||
     */
 | 
			
		||||
    public function index()
 | 
			
		||||
    {
 | 
			
		||||
        $addresses = $this->paginate($this->Addresses);
 | 
			
		||||
 | 
			
		||||
        $this->set(compact('addresses'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * View method
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|null $id Address id.
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Renders view
 | 
			
		||||
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
 | 
			
		||||
     */
 | 
			
		||||
    public function view($id = null)
 | 
			
		||||
    {
 | 
			
		||||
        $address = $this->Addresses->get($id, [
 | 
			
		||||
            'contain' => [],
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $this->set(compact('address'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add method
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public function add()
 | 
			
		||||
    {
 | 
			
		||||
        $address = $this->Addresses->newEmptyEntity();
 | 
			
		||||
        if ($this->request->is('post')) {
 | 
			
		||||
            $address = $this->Addresses->patchEntity($address, $this->request->getData());
 | 
			
		||||
            if ($this->Addresses->save($address)) {
 | 
			
		||||
                $this->Flash->success(__('The address has been saved.'));
 | 
			
		||||
 | 
			
		||||
                return $this->redirect(['action' => 'index']);
 | 
			
		||||
            }
 | 
			
		||||
            $this->Flash->error(__('The address could not be saved. Please, try again.'));
 | 
			
		||||
        }
 | 
			
		||||
        $this->set(compact('address'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Edit method
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|null $id Address id.
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise.
 | 
			
		||||
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
 | 
			
		||||
     */
 | 
			
		||||
    public function edit($id = null)
 | 
			
		||||
    {
 | 
			
		||||
        $address = $this->Addresses->get($id, [
 | 
			
		||||
            'contain' => [],
 | 
			
		||||
        ]);
 | 
			
		||||
        if ($this->request->is(['patch', 'post', 'put'])) {
 | 
			
		||||
            $address = $this->Addresses->patchEntity($address, $this->request->getData());
 | 
			
		||||
            if ($this->Addresses->save($address)) {
 | 
			
		||||
                $this->Flash->success(__('The address has been saved.'));
 | 
			
		||||
 | 
			
		||||
                return $this->redirect(['action' => 'index']);
 | 
			
		||||
            }
 | 
			
		||||
            $this->Flash->error(__('The address could not be saved. Please, try again.'));
 | 
			
		||||
        }
 | 
			
		||||
        $this->set(compact('address'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete method
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|null $id Address id.
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Redirects to index.
 | 
			
		||||
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
 | 
			
		||||
     */
 | 
			
		||||
    public function delete($id = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->request->allowMethod(['post', 'delete']);
 | 
			
		||||
        $address = $this->Addresses->get($id);
 | 
			
		||||
        if ($this->Addresses->delete($address)) {
 | 
			
		||||
            $this->Flash->success(__('The address has been deleted.'));
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->Flash->error(__('The address could not be deleted. Please, try again.'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->redirect(['action' => 'index']);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								CakePHP/src/Controller/UsersController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								CakePHP/src/Controller/UsersController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Users Controller
 | 
			
		||||
 *
 | 
			
		||||
 * @property \App\Model\Table\UsersTable $Users
 | 
			
		||||
 * @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
 | 
			
		||||
 */
 | 
			
		||||
class UsersController extends AppController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Index method
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Renders view
 | 
			
		||||
     */
 | 
			
		||||
    public function index()
 | 
			
		||||
    {
 | 
			
		||||
        $users = $this->paginate($this->Users);
 | 
			
		||||
 | 
			
		||||
        $this->set(compact('users'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * View method
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|null $id User id.
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Renders view
 | 
			
		||||
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
 | 
			
		||||
     */
 | 
			
		||||
    public function view($id = null)
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->Users->get($id, [
 | 
			
		||||
            'contain' => [],
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $this->set(compact('user'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add method
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public function add()
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->Users->newEmptyEntity();
 | 
			
		||||
        if ($this->request->is('post')) {
 | 
			
		||||
            $user = $this->Users->patchEntity($user, $this->request->getData());
 | 
			
		||||
            if ($this->Users->save($user)) {
 | 
			
		||||
                $this->Flash->success(__('The user has been saved.'));
 | 
			
		||||
 | 
			
		||||
                return $this->redirect(['action' => 'index']);
 | 
			
		||||
            }
 | 
			
		||||
            $this->Flash->error(__('The user could not be saved. Please, try again.'));
 | 
			
		||||
        }
 | 
			
		||||
        $this->set(compact('user'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Edit method
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|null $id User id.
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise.
 | 
			
		||||
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
 | 
			
		||||
     */
 | 
			
		||||
    public function edit($id = null)
 | 
			
		||||
    {
 | 
			
		||||
        $user = $this->Users->get($id, [
 | 
			
		||||
            'contain' => [],
 | 
			
		||||
        ]);
 | 
			
		||||
        if ($this->request->is(['patch', 'post', 'put'])) {
 | 
			
		||||
            $user = $this->Users->patchEntity($user, $this->request->getData());
 | 
			
		||||
            if ($this->Users->save($user)) {
 | 
			
		||||
                $this->Flash->success(__('The user has been saved.'));
 | 
			
		||||
 | 
			
		||||
                return $this->redirect(['action' => 'index']);
 | 
			
		||||
            }
 | 
			
		||||
            $this->Flash->error(__('The user could not be saved. Please, try again.'));
 | 
			
		||||
        }
 | 
			
		||||
        $this->set(compact('user'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete method
 | 
			
		||||
     *
 | 
			
		||||
     * @param string|null $id User id.
 | 
			
		||||
     * @return \Cake\Http\Response|null|void Redirects to index.
 | 
			
		||||
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
 | 
			
		||||
     */
 | 
			
		||||
    public function delete($id = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->request->allowMethod(['post', 'delete']);
 | 
			
		||||
        $user = $this->Users->get($id);
 | 
			
		||||
        if ($this->Users->delete($user)) {
 | 
			
		||||
            $this->Flash->success(__('The user has been deleted.'));
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->Flash->error(__('The user could not be deleted. Please, try again.'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->redirect(['action' => 'index']);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								CakePHP/src/Model/Entity/Address.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								CakePHP/src/Model/Entity/Address.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Model\Entity;
 | 
			
		||||
 | 
			
		||||
use Cake\ORM\Entity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Address Entity
 | 
			
		||||
 *
 | 
			
		||||
 * @property int $id
 | 
			
		||||
 * @property int $owner
 | 
			
		||||
 * @property string $first
 | 
			
		||||
 * @property string $last
 | 
			
		||||
 * @property string $street
 | 
			
		||||
 * @property string $zip
 | 
			
		||||
 * @property string $city
 | 
			
		||||
 * @property string $phone
 | 
			
		||||
 */
 | 
			
		||||
class Address extends Entity
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Fields that can be mass assigned using newEntity() or patchEntity().
 | 
			
		||||
     *
 | 
			
		||||
     * Note that when '*' is set to true, this allows all unspecified fields to
 | 
			
		||||
     * be mass assigned. For security purposes, it is advised to set '*' to false
 | 
			
		||||
     * (or remove it), and explicitly make individual fields accessible as needed.
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string, bool>
 | 
			
		||||
     */
 | 
			
		||||
    protected $_accessible = [
 | 
			
		||||
        'owner' => true,
 | 
			
		||||
        'first' => true,
 | 
			
		||||
        'last' => true,
 | 
			
		||||
        'street' => true,
 | 
			
		||||
        'zip' => true,
 | 
			
		||||
        'city' => true,
 | 
			
		||||
        'phone' => true,
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								CakePHP/src/Model/Entity/User.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								CakePHP/src/Model/Entity/User.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Model\Entity;
 | 
			
		||||
 | 
			
		||||
use Cake\ORM\Entity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * User Entity
 | 
			
		||||
 *
 | 
			
		||||
 * @property int $id
 | 
			
		||||
 * @property string $password
 | 
			
		||||
 * @property string $nick
 | 
			
		||||
 * @property string $first
 | 
			
		||||
 * @property string $last
 | 
			
		||||
 * @property bool $is_admin
 | 
			
		||||
 */
 | 
			
		||||
class User extends Entity
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Fields that can be mass assigned using newEntity() or patchEntity().
 | 
			
		||||
     *
 | 
			
		||||
     * Note that when '*' is set to true, this allows all unspecified fields to
 | 
			
		||||
     * be mass assigned. For security purposes, it is advised to set '*' to false
 | 
			
		||||
     * (or remove it), and explicitly make individual fields accessible as needed.
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string, bool>
 | 
			
		||||
     */
 | 
			
		||||
    protected $_accessible = [
 | 
			
		||||
        'password' => true,
 | 
			
		||||
        'nick' => true,
 | 
			
		||||
        'first' => true,
 | 
			
		||||
        'last' => true,
 | 
			
		||||
        'is_admin' => true,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fields that are excluded from JSON versions of the entity.
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string>
 | 
			
		||||
     */
 | 
			
		||||
    protected $_hidden = [
 | 
			
		||||
        'password',
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								CakePHP/src/Model/Table/AddressesTable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								CakePHP/src/Model/Table/AddressesTable.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Model\Table;
 | 
			
		||||
 | 
			
		||||
use Cake\ORM\Query;
 | 
			
		||||
use Cake\ORM\RulesChecker;
 | 
			
		||||
use Cake\ORM\Table;
 | 
			
		||||
use Cake\Validation\Validator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Addresses Model
 | 
			
		||||
 *
 | 
			
		||||
 * @method \App\Model\Entity\Address newEmptyEntity()
 | 
			
		||||
 * @method \App\Model\Entity\Address newEntity(array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address[] newEntities(array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address get($primaryKey, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address findOrCreate($search, ?callable $callback = null, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address[] patchEntities(iterable $entities, array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address|false save(\Cake\Datasource\EntityInterface $entity, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address[]|\Cake\Datasource\ResultSetInterface|false saveMany(iterable $entities, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address[]|\Cake\Datasource\ResultSetInterface saveManyOrFail(iterable $entities, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address[]|\Cake\Datasource\ResultSetInterface|false deleteMany(iterable $entities, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\Address[]|\Cake\Datasource\ResultSetInterface deleteManyOrFail(iterable $entities, $options = [])
 | 
			
		||||
 */
 | 
			
		||||
class AddressesTable extends Table
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize method
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $config The configuration for the Table.
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function initialize(array $config): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::initialize($config);
 | 
			
		||||
 | 
			
		||||
        $this->setTable('addresses');
 | 
			
		||||
        $this->setDisplayField('id');
 | 
			
		||||
        $this->setPrimaryKey('id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default validation rules.
 | 
			
		||||
     *
 | 
			
		||||
     * @param \Cake\Validation\Validator $validator Validator instance.
 | 
			
		||||
     * @return \Cake\Validation\Validator
 | 
			
		||||
     */
 | 
			
		||||
    public function validationDefault(Validator $validator): Validator
 | 
			
		||||
    {
 | 
			
		||||
        $validator
 | 
			
		||||
            ->integer('owner')
 | 
			
		||||
            ->requirePresence('owner', 'create')
 | 
			
		||||
            ->notEmptyString('owner');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('first')
 | 
			
		||||
            ->maxLength('first', 80)
 | 
			
		||||
            ->requirePresence('first', 'create')
 | 
			
		||||
            ->notEmptyString('first');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('last')
 | 
			
		||||
            ->maxLength('last', 80)
 | 
			
		||||
            ->requirePresence('last', 'create')
 | 
			
		||||
            ->notEmptyString('last');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('street')
 | 
			
		||||
            ->maxLength('street', 80)
 | 
			
		||||
            ->requirePresence('street', 'create')
 | 
			
		||||
            ->notEmptyString('street');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('zip')
 | 
			
		||||
            ->maxLength('zip', 10)
 | 
			
		||||
            ->requirePresence('zip', 'create')
 | 
			
		||||
            ->notEmptyString('zip');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('city')
 | 
			
		||||
            ->maxLength('city', 80)
 | 
			
		||||
            ->requirePresence('city', 'create')
 | 
			
		||||
            ->notEmptyString('city');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('phone')
 | 
			
		||||
            ->maxLength('phone', 30)
 | 
			
		||||
            ->requirePresence('phone', 'create')
 | 
			
		||||
            ->notEmptyString('phone');
 | 
			
		||||
 | 
			
		||||
        return $validator;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								CakePHP/src/Model/Table/UsersTable.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								CakePHP/src/Model/Table/UsersTable.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Model\Table;
 | 
			
		||||
 | 
			
		||||
use Cake\ORM\Query;
 | 
			
		||||
use Cake\ORM\RulesChecker;
 | 
			
		||||
use Cake\ORM\Table;
 | 
			
		||||
use Cake\Validation\Validator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Users Model
 | 
			
		||||
 *
 | 
			
		||||
 * @method \App\Model\Entity\User newEmptyEntity()
 | 
			
		||||
 * @method \App\Model\Entity\User newEntity(array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User[] newEntities(array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User get($primaryKey, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User findOrCreate($search, ?callable $callback = null, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User[] patchEntities(iterable $entities, array $data, array $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User|false save(\Cake\Datasource\EntityInterface $entity, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User saveOrFail(\Cake\Datasource\EntityInterface $entity, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface|false saveMany(iterable $entities, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface saveManyOrFail(iterable $entities, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface|false deleteMany(iterable $entities, $options = [])
 | 
			
		||||
 * @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface deleteManyOrFail(iterable $entities, $options = [])
 | 
			
		||||
 */
 | 
			
		||||
class UsersTable extends Table
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize method
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $config The configuration for the Table.
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function initialize(array $config): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::initialize($config);
 | 
			
		||||
 | 
			
		||||
        $this->setTable('users');
 | 
			
		||||
        $this->setDisplayField('id');
 | 
			
		||||
        $this->setPrimaryKey('id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Default validation rules.
 | 
			
		||||
     *
 | 
			
		||||
     * @param \Cake\Validation\Validator $validator Validator instance.
 | 
			
		||||
     * @return \Cake\Validation\Validator
 | 
			
		||||
     */
 | 
			
		||||
    public function validationDefault(Validator $validator): Validator
 | 
			
		||||
    {
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('password')
 | 
			
		||||
            ->maxLength('password', 256)
 | 
			
		||||
            ->requirePresence('password', 'create')
 | 
			
		||||
            ->notEmptyString('password');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('nick')
 | 
			
		||||
            ->maxLength('nick', 20)
 | 
			
		||||
            ->requirePresence('nick', 'create')
 | 
			
		||||
            ->notEmptyString('nick')
 | 
			
		||||
            ->add('nick', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('first')
 | 
			
		||||
            ->maxLength('first', 40)
 | 
			
		||||
            ->requirePresence('first', 'create')
 | 
			
		||||
            ->notEmptyString('first');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->scalar('last')
 | 
			
		||||
            ->maxLength('last', 40)
 | 
			
		||||
            ->requirePresence('last', 'create')
 | 
			
		||||
            ->notEmptyString('last');
 | 
			
		||||
 | 
			
		||||
        $validator
 | 
			
		||||
            ->boolean('is_admin')
 | 
			
		||||
            ->requirePresence('is_admin', 'create')
 | 
			
		||||
            ->notEmptyString('is_admin');
 | 
			
		||||
 | 
			
		||||
        return $validator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a rules checker object that will be used for validating
 | 
			
		||||
     * application integrity.
 | 
			
		||||
     *
 | 
			
		||||
     * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
 | 
			
		||||
     * @return \Cake\ORM\RulesChecker
 | 
			
		||||
     */
 | 
			
		||||
    public function buildRules(RulesChecker $rules): RulesChecker
 | 
			
		||||
    {
 | 
			
		||||
        $rules->add($rules->isUnique(['nick']), ['errorField' => 'nick']);
 | 
			
		||||
 | 
			
		||||
        return $rules;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								CakePHP/templates/Addresses/add.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								CakePHP/templates/Addresses/add.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var \App\Model\Entity\Address $address
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <aside class="column">
 | 
			
		||||
        <div class="side-nav">
 | 
			
		||||
            <h4 class="heading"><?= __('Actions') ?></h4>
 | 
			
		||||
            <?= $this->Html->link(__('List Addresses'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </aside>
 | 
			
		||||
    <div class="column-responsive column-80">
 | 
			
		||||
        <div class="addresses form content">
 | 
			
		||||
            <?= $this->Form->create($address) ?>
 | 
			
		||||
            <fieldset>
 | 
			
		||||
                <legend><?= __('Add Address') ?></legend>
 | 
			
		||||
                <?php
 | 
			
		||||
                    echo $this->Form->control('owner');
 | 
			
		||||
                    echo $this->Form->control('first');
 | 
			
		||||
                    echo $this->Form->control('last');
 | 
			
		||||
                    echo $this->Form->control('street');
 | 
			
		||||
                    echo $this->Form->control('zip');
 | 
			
		||||
                    echo $this->Form->control('city');
 | 
			
		||||
                    echo $this->Form->control('phone');
 | 
			
		||||
                ?>
 | 
			
		||||
            </fieldset>
 | 
			
		||||
            <?= $this->Form->button(__('Submit')) ?>
 | 
			
		||||
            <?= $this->Form->end() ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										38
									
								
								CakePHP/templates/Addresses/edit.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								CakePHP/templates/Addresses/edit.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var \App\Model\Entity\Address $address
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <aside class="column">
 | 
			
		||||
        <div class="side-nav">
 | 
			
		||||
            <h4 class="heading"><?= __('Actions') ?></h4>
 | 
			
		||||
            <?= $this->Form->postLink(
 | 
			
		||||
                __('Delete'),
 | 
			
		||||
                ['action' => 'delete', $address->id],
 | 
			
		||||
                ['confirm' => __('Are you sure you want to delete # {0}?', $address->id), 'class' => 'side-nav-item']
 | 
			
		||||
            ) ?>
 | 
			
		||||
            <?= $this->Html->link(__('List Addresses'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </aside>
 | 
			
		||||
    <div class="column-responsive column-80">
 | 
			
		||||
        <div class="addresses form content">
 | 
			
		||||
            <?= $this->Form->create($address) ?>
 | 
			
		||||
            <fieldset>
 | 
			
		||||
                <legend><?= __('Edit Address') ?></legend>
 | 
			
		||||
                <?php
 | 
			
		||||
                    echo $this->Form->control('owner');
 | 
			
		||||
                    echo $this->Form->control('first');
 | 
			
		||||
                    echo $this->Form->control('last');
 | 
			
		||||
                    echo $this->Form->control('street');
 | 
			
		||||
                    echo $this->Form->control('zip');
 | 
			
		||||
                    echo $this->Form->control('city');
 | 
			
		||||
                    echo $this->Form->control('phone');
 | 
			
		||||
                ?>
 | 
			
		||||
            </fieldset>
 | 
			
		||||
            <?= $this->Form->button(__('Submit')) ?>
 | 
			
		||||
            <?= $this->Form->end() ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										56
									
								
								CakePHP/templates/Addresses/index.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								CakePHP/templates/Addresses/index.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var iterable<\App\Model\Entity\Address> $addresses
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="addresses index content">
 | 
			
		||||
    <?= $this->Html->link(__('New Address'), ['action' => 'add'], ['class' => 'button float-right']) ?>
 | 
			
		||||
    <h3><?= __('Addresses') ?></h3>
 | 
			
		||||
    <div class="table-responsive">
 | 
			
		||||
        <table>
 | 
			
		||||
            <thead>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('id') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('owner') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('first') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('last') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('street') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('zip') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('city') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('phone') ?></th>
 | 
			
		||||
                    <th class="actions"><?= __('Actions') ?></th>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </thead>
 | 
			
		||||
            <tbody>
 | 
			
		||||
                <?php foreach ($addresses as $address): ?>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td><?= $this->Number->format($address->id) ?></td>
 | 
			
		||||
                    <td><?= $this->Number->format($address->owner) ?></td>
 | 
			
		||||
                    <td><?= h($address->first) ?></td>
 | 
			
		||||
                    <td><?= h($address->last) ?></td>
 | 
			
		||||
                    <td><?= h($address->street) ?></td>
 | 
			
		||||
                    <td><?= h($address->zip) ?></td>
 | 
			
		||||
                    <td><?= h($address->city) ?></td>
 | 
			
		||||
                    <td><?= h($address->phone) ?></td>
 | 
			
		||||
                    <td class="actions">
 | 
			
		||||
                        <?= $this->Html->link(__('View'), ['action' => 'view', $address->id]) ?>
 | 
			
		||||
                        <?= $this->Html->link(__('Edit'), ['action' => 'edit', $address->id]) ?>
 | 
			
		||||
                        <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $address->id], ['confirm' => __('Are you sure you want to delete # {0}?', $address->id)]) ?>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <?php endforeach; ?>
 | 
			
		||||
            </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="paginator">
 | 
			
		||||
        <ul class="pagination">
 | 
			
		||||
            <?= $this->Paginator->first('<< ' . __('first')) ?>
 | 
			
		||||
            <?= $this->Paginator->prev('< ' . __('previous')) ?>
 | 
			
		||||
            <?= $this->Paginator->numbers() ?>
 | 
			
		||||
            <?= $this->Paginator->next(__('next') . ' >') ?>
 | 
			
		||||
            <?= $this->Paginator->last(__('last') . ' >>') ?>
 | 
			
		||||
        </ul>
 | 
			
		||||
        <p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										56
									
								
								CakePHP/templates/Addresses/view.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								CakePHP/templates/Addresses/view.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var \App\Model\Entity\Address $address
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <aside class="column">
 | 
			
		||||
        <div class="side-nav">
 | 
			
		||||
            <h4 class="heading"><?= __('Actions') ?></h4>
 | 
			
		||||
            <?= $this->Html->link(__('Edit Address'), ['action' => 'edit', $address->id], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
            <?= $this->Form->postLink(__('Delete Address'), ['action' => 'delete', $address->id], ['confirm' => __('Are you sure you want to delete # {0}?', $address->id), 'class' => 'side-nav-item']) ?>
 | 
			
		||||
            <?= $this->Html->link(__('List Addresses'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
            <?= $this->Html->link(__('New Address'), ['action' => 'add'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </aside>
 | 
			
		||||
    <div class="column-responsive column-80">
 | 
			
		||||
        <div class="addresses view content">
 | 
			
		||||
            <h3><?= h($address->id) ?></h3>
 | 
			
		||||
            <table>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('First') ?></th>
 | 
			
		||||
                    <td><?= h($address->first) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Last') ?></th>
 | 
			
		||||
                    <td><?= h($address->last) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Street') ?></th>
 | 
			
		||||
                    <td><?= h($address->street) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Zip') ?></th>
 | 
			
		||||
                    <td><?= h($address->zip) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('City') ?></th>
 | 
			
		||||
                    <td><?= h($address->city) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Phone') ?></th>
 | 
			
		||||
                    <td><?= h($address->phone) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Id') ?></th>
 | 
			
		||||
                    <td><?= $this->Number->format($address->id) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Owner') ?></th>
 | 
			
		||||
                    <td><?= $this->Number->format($address->owner) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </table>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										0
									
								
								CakePHP/templates/App/index.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								CakePHP/templates/App/index.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								CakePHP/templates/Pages/main.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								CakePHP/templates/Pages/main.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										31
									
								
								CakePHP/templates/Users/add.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								CakePHP/templates/Users/add.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var \App\Model\Entity\User $user
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <aside class="column">
 | 
			
		||||
        <div class="side-nav">
 | 
			
		||||
            <h4 class="heading"><?= __('Actions') ?></h4>
 | 
			
		||||
            <?= $this->Html->link(__('List Users'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </aside>
 | 
			
		||||
    <div class="column-responsive column-80">
 | 
			
		||||
        <div class="users form content">
 | 
			
		||||
            <?= $this->Form->create($user) ?>
 | 
			
		||||
            <fieldset>
 | 
			
		||||
                <legend><?= __('Add User') ?></legend>
 | 
			
		||||
                <?php
 | 
			
		||||
                    echo $this->Form->control('password');
 | 
			
		||||
                    echo $this->Form->control('nick');
 | 
			
		||||
                    echo $this->Form->control('first');
 | 
			
		||||
                    echo $this->Form->control('last');
 | 
			
		||||
                    echo $this->Form->control('is_admin');
 | 
			
		||||
                ?>
 | 
			
		||||
            </fieldset>
 | 
			
		||||
            <?= $this->Form->button(__('Submit')) ?>
 | 
			
		||||
            <?= $this->Form->end() ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										36
									
								
								CakePHP/templates/Users/edit.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								CakePHP/templates/Users/edit.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var \App\Model\Entity\User $user
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <aside class="column">
 | 
			
		||||
        <div class="side-nav">
 | 
			
		||||
            <h4 class="heading"><?= __('Actions') ?></h4>
 | 
			
		||||
            <?= $this->Form->postLink(
 | 
			
		||||
                __('Delete'),
 | 
			
		||||
                ['action' => 'delete', $user->id],
 | 
			
		||||
                ['confirm' => __('Are you sure you want to delete # {0}?', $user->id), 'class' => 'side-nav-item']
 | 
			
		||||
            ) ?>
 | 
			
		||||
            <?= $this->Html->link(__('List Users'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </aside>
 | 
			
		||||
    <div class="column-responsive column-80">
 | 
			
		||||
        <div class="users form content">
 | 
			
		||||
            <?= $this->Form->create($user) ?>
 | 
			
		||||
            <fieldset>
 | 
			
		||||
                <legend><?= __('Edit User') ?></legend>
 | 
			
		||||
                <?php
 | 
			
		||||
                    echo $this->Form->control('password');
 | 
			
		||||
                    echo $this->Form->control('nick');
 | 
			
		||||
                    echo $this->Form->control('first');
 | 
			
		||||
                    echo $this->Form->control('last');
 | 
			
		||||
                    echo $this->Form->control('is_admin');
 | 
			
		||||
                ?>
 | 
			
		||||
            </fieldset>
 | 
			
		||||
            <?= $this->Form->button(__('Submit')) ?>
 | 
			
		||||
            <?= $this->Form->end() ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										50
									
								
								CakePHP/templates/Users/index.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								CakePHP/templates/Users/index.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var iterable<\App\Model\Entity\User> $users
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="users index content">
 | 
			
		||||
    <?= $this->Html->link(__('New User'), ['action' => 'add'], ['class' => 'button float-right']) ?>
 | 
			
		||||
    <h3><?= __('Users') ?></h3>
 | 
			
		||||
    <div class="table-responsive">
 | 
			
		||||
        <table>
 | 
			
		||||
            <thead>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('id') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('nick') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('first') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('last') ?></th>
 | 
			
		||||
                    <th><?= $this->Paginator->sort('is_admin') ?></th>
 | 
			
		||||
                    <th class="actions"><?= __('Actions') ?></th>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </thead>
 | 
			
		||||
            <tbody>
 | 
			
		||||
                <?php foreach ($users as $user): ?>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td><?= $this->Number->format($user->id) ?></td>
 | 
			
		||||
                    <td><?= h($user->nick) ?></td>
 | 
			
		||||
                    <td><?= h($user->first) ?></td>
 | 
			
		||||
                    <td><?= h($user->last) ?></td>
 | 
			
		||||
                    <td><?= h($user->is_admin) ?></td>
 | 
			
		||||
                    <td class="actions">
 | 
			
		||||
                        <?= $this->Html->link(__('View'), ['action' => 'view', $user->id]) ?>
 | 
			
		||||
                        <?= $this->Html->link(__('Edit'), ['action' => 'edit', $user->id]) ?>
 | 
			
		||||
                        <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]) ?>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <?php endforeach; ?>
 | 
			
		||||
            </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="paginator">
 | 
			
		||||
        <ul class="pagination">
 | 
			
		||||
            <?= $this->Paginator->first('<< ' . __('first')) ?>
 | 
			
		||||
            <?= $this->Paginator->prev('< ' . __('previous')) ?>
 | 
			
		||||
            <?= $this->Paginator->numbers() ?>
 | 
			
		||||
            <?= $this->Paginator->next(__('next') . ' >') ?>
 | 
			
		||||
            <?= $this->Paginator->last(__('last') . ' >>') ?>
 | 
			
		||||
        </ul>
 | 
			
		||||
        <p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										1
									
								
								CakePHP/templates/Users/login.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								CakePHP/templates/Users/login.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<?php
 | 
			
		||||
							
								
								
									
										44
									
								
								CakePHP/templates/Users/view.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								CakePHP/templates/Users/view.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var \App\Model\Entity\User $user
 | 
			
		||||
 */
 | 
			
		||||
?>
 | 
			
		||||
<div class="row">
 | 
			
		||||
    <aside class="column">
 | 
			
		||||
        <div class="side-nav">
 | 
			
		||||
            <h4 class="heading"><?= __('Actions') ?></h4>
 | 
			
		||||
            <?= $this->Html->link(__('Edit User'), ['action' => 'edit', $user->id], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
            <?= $this->Form->postLink(__('Delete User'), ['action' => 'delete', $user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id), 'class' => 'side-nav-item']) ?>
 | 
			
		||||
            <?= $this->Html->link(__('List Users'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
            <?= $this->Html->link(__('New User'), ['action' => 'add'], ['class' => 'side-nav-item']) ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    </aside>
 | 
			
		||||
    <div class="column-responsive column-80">
 | 
			
		||||
        <div class="users view content">
 | 
			
		||||
            <h3><?= h($user->id) ?></h3>
 | 
			
		||||
            <table>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Nick') ?></th>
 | 
			
		||||
                    <td><?= h($user->nick) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('First') ?></th>
 | 
			
		||||
                    <td><?= h($user->first) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Last') ?></th>
 | 
			
		||||
                    <td><?= h($user->last) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Id') ?></th>
 | 
			
		||||
                    <td><?= $this->Number->format($user->id) ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <th><?= __('Is Admin') ?></th>
 | 
			
		||||
                    <td><?= $user->is_admin ? __('Yes') : __('No'); ?></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </table>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										11
									
								
								CakePHP/templates/element/flash/info.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								CakePHP/templates/element/flash/info.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var array $params
 | 
			
		||||
 * @var string $message
 | 
			
		||||
 */
 | 
			
		||||
if (!isset($params['escape']) || $params['escape'] !== false) {
 | 
			
		||||
    $message = h($message);
 | 
			
		||||
}
 | 
			
		||||
?>
 | 
			
		||||
<div class="message" onclick="this.classList.add('hidden');"><?= $message ?></div>
 | 
			
		||||
							
								
								
									
										11
									
								
								CakePHP/templates/element/flash/warning.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								CakePHP/templates/element/flash/warning.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * @var \App\View\AppView $this
 | 
			
		||||
 * @var array $params
 | 
			
		||||
 * @var string $message
 | 
			
		||||
 */
 | 
			
		||||
if (!isset($params['escape']) || $params['escape'] !== false) {
 | 
			
		||||
    $message = h($message);
 | 
			
		||||
}
 | 
			
		||||
?>
 | 
			
		||||
<div class="message warning" onclick="this.classList.add('hidden');"><?= $message ?></div>
 | 
			
		||||
							
								
								
									
										34
									
								
								CakePHP/tests/Fixture/AddressesFixture.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								CakePHP/tests/Fixture/AddressesFixture.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Test\Fixture;
 | 
			
		||||
 | 
			
		||||
use Cake\TestSuite\Fixture\TestFixture;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * AddressesFixture
 | 
			
		||||
 */
 | 
			
		||||
class AddressesFixture extends TestFixture
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Init method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function init(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->records = [
 | 
			
		||||
            [
 | 
			
		||||
                'id' => 1,
 | 
			
		||||
                'owner' => 1,
 | 
			
		||||
                'first' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'last' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'street' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'zip' => 'Lorem ip',
 | 
			
		||||
                'city' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'phone' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
        parent::init();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								CakePHP/tests/Fixture/UsersFixture.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								CakePHP/tests/Fixture/UsersFixture.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Test\Fixture;
 | 
			
		||||
 | 
			
		||||
use Cake\TestSuite\Fixture\TestFixture;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * UsersFixture
 | 
			
		||||
 */
 | 
			
		||||
class UsersFixture extends TestFixture
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Init method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function init(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->records = [
 | 
			
		||||
            [
 | 
			
		||||
                'id' => 1,
 | 
			
		||||
                'password' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'nick' => 'Lorem ipsum dolor ',
 | 
			
		||||
                'first' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'last' => 'Lorem ipsum dolor sit amet',
 | 
			
		||||
                'is_admin' => 1,
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
        parent::init();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Test\TestCase\Controller;
 | 
			
		||||
 | 
			
		||||
use App\Controller\AddressesController;
 | 
			
		||||
use Cake\TestSuite\IntegrationTestTrait;
 | 
			
		||||
use Cake\TestSuite\TestCase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * App\Controller\AddressesController Test Case
 | 
			
		||||
 *
 | 
			
		||||
 * @uses \App\Controller\AddressesController
 | 
			
		||||
 */
 | 
			
		||||
class AddressesControllerTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    use IntegrationTestTrait;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fixtures
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string>
 | 
			
		||||
     */
 | 
			
		||||
    protected $fixtures = [
 | 
			
		||||
        'app.Addresses',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test index method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\AddressesController::index()
 | 
			
		||||
     */
 | 
			
		||||
    public function testIndex(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test view method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\AddressesController::view()
 | 
			
		||||
     */
 | 
			
		||||
    public function testView(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test add method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\AddressesController::add()
 | 
			
		||||
     */
 | 
			
		||||
    public function testAdd(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test edit method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\AddressesController::edit()
 | 
			
		||||
     */
 | 
			
		||||
    public function testEdit(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test delete method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\AddressesController::delete()
 | 
			
		||||
     */
 | 
			
		||||
    public function testDelete(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								CakePHP/tests/TestCase/Controller/UsersControllerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								CakePHP/tests/TestCase/Controller/UsersControllerTest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Test\TestCase\Controller;
 | 
			
		||||
 | 
			
		||||
use App\Controller\UsersController;
 | 
			
		||||
use Cake\TestSuite\IntegrationTestTrait;
 | 
			
		||||
use Cake\TestSuite\TestCase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * App\Controller\UsersController Test Case
 | 
			
		||||
 *
 | 
			
		||||
 * @uses \App\Controller\UsersController
 | 
			
		||||
 */
 | 
			
		||||
class UsersControllerTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    use IntegrationTestTrait;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fixtures
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string>
 | 
			
		||||
     */
 | 
			
		||||
    protected $fixtures = [
 | 
			
		||||
        'app.Users',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test index method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\UsersController::index()
 | 
			
		||||
     */
 | 
			
		||||
    public function testIndex(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test view method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\UsersController::view()
 | 
			
		||||
     */
 | 
			
		||||
    public function testView(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test add method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\UsersController::add()
 | 
			
		||||
     */
 | 
			
		||||
    public function testAdd(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test edit method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\UsersController::edit()
 | 
			
		||||
     */
 | 
			
		||||
    public function testEdit(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test delete method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Controller\UsersController::delete()
 | 
			
		||||
     */
 | 
			
		||||
    public function testDelete(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								CakePHP/tests/TestCase/Model/Table/AddressesTableTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								CakePHP/tests/TestCase/Model/Table/AddressesTableTest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Test\TestCase\Model\Table;
 | 
			
		||||
 | 
			
		||||
use App\Model\Table\AddressesTable;
 | 
			
		||||
use Cake\TestSuite\TestCase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * App\Model\Table\AddressesTable Test Case
 | 
			
		||||
 */
 | 
			
		||||
class AddressesTableTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Test subject
 | 
			
		||||
     *
 | 
			
		||||
     * @var \App\Model\Table\AddressesTable
 | 
			
		||||
     */
 | 
			
		||||
    protected $Addresses;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fixtures
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string>
 | 
			
		||||
     */
 | 
			
		||||
    protected $fixtures = [
 | 
			
		||||
        'app.Addresses',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setUp method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    protected function setUp(): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
        $config = $this->getTableLocator()->exists('Addresses') ? [] : ['className' => AddressesTable::class];
 | 
			
		||||
        $this->Addresses = $this->getTableLocator()->get('Addresses', $config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * tearDown method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    protected function tearDown(): void
 | 
			
		||||
    {
 | 
			
		||||
        unset($this->Addresses);
 | 
			
		||||
 | 
			
		||||
        parent::tearDown();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test validationDefault method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Model\Table\AddressesTable::validationDefault()
 | 
			
		||||
     */
 | 
			
		||||
    public function testValidationDefault(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								CakePHP/tests/TestCase/Model/Table/UsersTableTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								CakePHP/tests/TestCase/Model/Table/UsersTableTest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
<?php
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace App\Test\TestCase\Model\Table;
 | 
			
		||||
 | 
			
		||||
use App\Model\Table\UsersTable;
 | 
			
		||||
use Cake\TestSuite\TestCase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * App\Model\Table\UsersTable Test Case
 | 
			
		||||
 */
 | 
			
		||||
class UsersTableTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Test subject
 | 
			
		||||
     *
 | 
			
		||||
     * @var \App\Model\Table\UsersTable
 | 
			
		||||
     */
 | 
			
		||||
    protected $Users;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fixtures
 | 
			
		||||
     *
 | 
			
		||||
     * @var array<string>
 | 
			
		||||
     */
 | 
			
		||||
    protected $fixtures = [
 | 
			
		||||
        'app.Users',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setUp method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    protected function setUp(): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
        $config = $this->getTableLocator()->exists('Users') ? [] : ['className' => UsersTable::class];
 | 
			
		||||
        $this->Users = $this->getTableLocator()->get('Users', $config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * tearDown method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    protected function tearDown(): void
 | 
			
		||||
    {
 | 
			
		||||
        unset($this->Users);
 | 
			
		||||
 | 
			
		||||
        parent::tearDown();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test validationDefault method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Model\Table\UsersTable::validationDefault()
 | 
			
		||||
     */
 | 
			
		||||
    public function testValidationDefault(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Test buildRules method
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     * @uses \App\Model\Table\UsersTable::buildRules()
 | 
			
		||||
     */
 | 
			
		||||
    public function testBuildRules(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->markTestIncomplete('Not implemented yet.');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								CakePHP/tests/schema.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								CakePHP/tests/schema.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
-- Test database schema.
 | 
			
		||||
--
 | 
			
		||||
-- If you are not using CakePHP migrations you can put
 | 
			
		||||
-- your application's schema in this file and use it in tests.
 | 
			
		||||
							
								
								
									
										8
									
								
								CakePHP/webroot/css/normalize.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								CakePHP/webroot/css/normalize.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Minified by jsDelivr using clean-css v4.2.1.
 | 
			
		||||
 * Original file: /npm/normalize.css@8.0.1/normalize.css
 | 
			
		||||
 *
 | 
			
		||||
 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
 | 
			
		||||
 */
 | 
			
		||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
 | 
			
		||||
html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
As I was not allowed to use any framework, respectively no foreign code, most of the time was spent, well creating some kind of framework myself. :-)
 | 
			
		||||
 | 
			
		||||
The address book itself was than done in a few hours.
 | 
			
		||||
The address book itself was then done in a few hours.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								addressbook.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								addressbook.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
-- MariaDB dump 10.19  Distrib 10.5.15-MariaDB, for debian-linux-gnu (x86_64)
 | 
			
		||||
--
 | 
			
		||||
-- Host: localhost    Database: tracer_addressbook
 | 
			
		||||
-- ------------------------------------------------------
 | 
			
		||||
-- Server version	10.5.15-MariaDB-0+deb11u1-log
 | 
			
		||||
 | 
			
		||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
 | 
			
		||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
 | 
			
		||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
 | 
			
		||||
/*!40101 SET NAMES utf8 */;
 | 
			
		||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
 | 
			
		||||
/*!40103 SET TIME_ZONE='+00:00' */;
 | 
			
		||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
 | 
			
		||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
 | 
			
		||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
 | 
			
		||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Table structure for table `addresses`
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
DROP TABLE IF EXISTS `addresses`;
 | 
			
		||||
/*!40101 SET @saved_cs_client     = @@character_set_client */;
 | 
			
		||||
/*!40101 SET character_set_client = utf8 */;
 | 
			
		||||
CREATE TABLE `addresses` (
 | 
			
		||||
  `id` int(11) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
  `owner` int(11) NOT NULL,
 | 
			
		||||
  `first` varchar(80) NOT NULL,
 | 
			
		||||
  `last` varchar(80) NOT NULL,
 | 
			
		||||
  `street` varchar(80) NOT NULL,
 | 
			
		||||
  `zip` varchar(10) NOT NULL,
 | 
			
		||||
  `city` varchar(80) NOT NULL,
 | 
			
		||||
  `phone` varchar(30) NOT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`),
 | 
			
		||||
  KEY `fk_user` (`owner`),
 | 
			
		||||
  CONSTRAINT `fk_user` FOREIGN KEY (`owner`) REFERENCES `users` (`id`)
 | 
			
		||||
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4;
 | 
			
		||||
/*!40101 SET character_set_client = @saved_cs_client */;
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Dumping data for table `addresses`
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
LOCK TABLES `addresses` WRITE;
 | 
			
		||||
/*!40000 ALTER TABLE `addresses` DISABLE KEYS */;
 | 
			
		||||
INSERT INTO `addresses` VALUES (1,2,'a \"test\"','a','Webfoot Street','1313','Duckburg2','555-12345'),(4,1,'c','b','street4','zip4','city4','phone4'),(6,1,'Huey','Duck','Webfoot Street','1010','Duckburg','555.3456'),(7,1,'Dewey','Duck','Webfoot Street','2020','Duckburg','555-9876'),(8,1,'Louie','Duck','Webfoot Street','3030','Duckburg 3','555-8765'),(11,1,'b','Clapton','sdfg','12456^^^>','https://xd.adobe.com/','23343'),(14,1,'d','aa','','','<script>alert(\'test\')</script>','x'),(16,1,'Adam \"The Badass\"','Black','piouhpouhpouh','132213','piugpiugh','9760978');
 | 
			
		||||
/*!40000 ALTER TABLE `addresses` ENABLE KEYS */;
 | 
			
		||||
UNLOCK TABLES;
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Table structure for table `users`
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
DROP TABLE IF EXISTS `users`;
 | 
			
		||||
/*!40101 SET @saved_cs_client     = @@character_set_client */;
 | 
			
		||||
/*!40101 SET character_set_client = utf8 */;
 | 
			
		||||
CREATE TABLE `users` (
 | 
			
		||||
  `id` int(11) NOT NULL AUTO_INCREMENT,
 | 
			
		||||
  `password` varchar(256) NOT NULL,
 | 
			
		||||
  `nick` varchar(20) NOT NULL,
 | 
			
		||||
  `first` varchar(40) NOT NULL,
 | 
			
		||||
  `last` varchar(40) NOT NULL,
 | 
			
		||||
  `is_admin` tinyint(1) NOT NULL,
 | 
			
		||||
  PRIMARY KEY (`id`),
 | 
			
		||||
  UNIQUE KEY `nick` (`nick`)
 | 
			
		||||
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4;
 | 
			
		||||
/*!40101 SET character_set_client = @saved_cs_client */;
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Dumping data for table `users`
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
LOCK TABLES `users` WRITE;
 | 
			
		||||
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
 | 
			
		||||
INSERT INTO `users` VALUES (1,'$argon2i$v=19$m=65536,t=4,p=1$OFV0Rnl6OXNWZXZJNTFjTw$fC9K1ykszZ/UaEm21XR9M3+XxnBc+dZ7PRIn5aaGw8I','donald','Donald','Duck',1),(2,'$argon2i$v=19$m=65536,t=4,p=1$NVRKNm0xUmplYkcwTFZXdw$GLp1jjLDBRjKSw6nH8SqqSls6fQPi4Hb7ot0k3naf5s','Daisy','Daisy','Duck',0);
 | 
			
		||||
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
 | 
			
		||||
UNLOCK TABLES;
 | 
			
		||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
 | 
			
		||||
 | 
			
		||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
 | 
			
		||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
 | 
			
		||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
 | 
			
		||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
 | 
			
		||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
 | 
			
		||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
 | 
			
		||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
 | 
			
		||||
 | 
			
		||||
-- Dump completed on 2022-11-01 18:37:04
 | 
			
		||||
							
								
								
									
										161
									
								
								app/Controllers/AddressBookAdminController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								app/Controllers/AddressBookAdminController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
 | 
			
		||||
use App\Entity\User;
 | 
			
		||||
use App\Repository\UserRepository;
 | 
			
		||||
use App\Service\Router;
 | 
			
		||||
use App\Service\Template;
 | 
			
		||||
 | 
			
		||||
class AddressBookAdminController
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private readonly Template       $template,
 | 
			
		||||
        private readonly User           $user,
 | 
			
		||||
        private readonly UserRepository $userRepository,
 | 
			
		||||
        private readonly Router         $router
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function adminCheck(): void
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->user->isAdmin()) {
 | 
			
		||||
            $this->template->render(templateName: 'status/403.html.php', vars: [
 | 
			
		||||
                'user'   => $this->user,
 | 
			
		||||
                'router' => $this->router
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function admin(): never
 | 
			
		||||
    {
 | 
			
		||||
        $this->adminCheck();
 | 
			
		||||
        $this->template->render(templateName: 'admin/index.html.php', vars: [
 | 
			
		||||
            'user'   => $this->user,
 | 
			
		||||
            'router' => $this->router
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function adminUser(): never
 | 
			
		||||
    {
 | 
			
		||||
        $this->adminCheck();
 | 
			
		||||
 | 
			
		||||
        $users = $this->userRepository->findAll();
 | 
			
		||||
 | 
			
		||||
        $this->template->render(templateName: 'admin/users.html.php', vars: [
 | 
			
		||||
            'user'   => $this->user,
 | 
			
		||||
            'users'  => $users,
 | 
			
		||||
            'router' => $this->router
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function adminUserEdit(array $parameters): never
 | 
			
		||||
    {
 | 
			
		||||
        $this->adminCheck();
 | 
			
		||||
 | 
			
		||||
        if (!empty($_POST)) {
 | 
			
		||||
            if (!empty($_POST['is_admin'])) {
 | 
			
		||||
                $isAdmin = 1;
 | 
			
		||||
            } else {
 | 
			
		||||
                $isAdmin = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (empty($_POST['new_password'])) {
 | 
			
		||||
                $current = $this->userRepository->findByID(id: $_POST['id']);
 | 
			
		||||
                $password = $current->getPassword();
 | 
			
		||||
                $updateUser = new User(nick: $_POST['nick'], password: $password, first: $_POST['first'], last: $_POST['last'], id: $_POST['id'], isAdmin: $isAdmin);
 | 
			
		||||
            } else {
 | 
			
		||||
                $password = $_POST['new_password'];
 | 
			
		||||
                $updateUser = new User(nick: $_POST['nick'], newPassword: $password, first: $_POST['first'], last: $_POST['last'], id: $_POST['id'], isAdmin: $isAdmin);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->userRepository->update(user: $updateUser);
 | 
			
		||||
 | 
			
		||||
            $users = $this->userRepository->findAll();
 | 
			
		||||
 | 
			
		||||
            $this->template->render(templateName: 'admin/users.html.php', vars: [
 | 
			
		||||
                'user'   => $this->user,
 | 
			
		||||
                'users'  => $users,
 | 
			
		||||
                'router' => $this->router
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $editUser = $this->userRepository->findByNick(nick: $parameters['nick']);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $this->template->render(templateName: 'admin/users_edit.html.php', vars: [
 | 
			
		||||
            'user'     => $this->user,
 | 
			
		||||
            'editUser' => $editUser,
 | 
			
		||||
            'router'   => $this->router
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function adminUserAdd(): never
 | 
			
		||||
    {
 | 
			
		||||
        $this->adminCheck();
 | 
			
		||||
 | 
			
		||||
        $nick = $_POST['nick'];
 | 
			
		||||
 | 
			
		||||
        if ($this->userRepository->findByNick(nick: $nick)) {
 | 
			
		||||
            die("User: $nick already exists");
 | 
			
		||||
        }
 | 
			
		||||
        if (!empty($_POST)) {
 | 
			
		||||
            $isAdmin = empty($_POST['is_admin']) ? 0 : 1;
 | 
			
		||||
            $user = new User(nick: $_POST['nick'], newPassword: $_POST['new_password'], first: $_POST['first'], last: $_POST['last'], isAdmin: $isAdmin);
 | 
			
		||||
 | 
			
		||||
            if ($this->userRepository->insert(user: $user)) {
 | 
			
		||||
                $users = $this->userRepository->findAll();
 | 
			
		||||
 | 
			
		||||
                $this->template->render(templateName: 'admin/users.html.php', vars: [
 | 
			
		||||
                    'user'   => $this->user,
 | 
			
		||||
                    'users'  => $users,
 | 
			
		||||
                    'router' => $this->router
 | 
			
		||||
                ]);
 | 
			
		||||
            } else {
 | 
			
		||||
                die("Error inserting user");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->template->render(templateName: 'admin/users_add.html.php', vars: [
 | 
			
		||||
            'user'   => $this->user,
 | 
			
		||||
            'router' => $this->router
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function adminUserDelete(array $parameters): never
 | 
			
		||||
    {
 | 
			
		||||
        $this->adminCheck();
 | 
			
		||||
 | 
			
		||||
        $nick = $parameters['nick'];
 | 
			
		||||
        if ($user = $this->userRepository->findByNick(nick: $nick)) {
 | 
			
		||||
            if ($this->userRepository->delete(user: $user)) {
 | 
			
		||||
                $users = $this->userRepository->findAll();
 | 
			
		||||
 | 
			
		||||
                $this->template->render(templateName: 'admin/users.html.php', vars: [
 | 
			
		||||
                    'user'   => $this->user,
 | 
			
		||||
                    'users'  => $users,
 | 
			
		||||
                    'router' => $this->router
 | 
			
		||||
                ]);
 | 
			
		||||
            } else {
 | 
			
		||||
                die("Error deleting user");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->template->render(templateName: 'status/404.html.php', vars: [
 | 
			
		||||
                'user'   => $this->user,
 | 
			
		||||
                'router' => $this->router
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										133
									
								
								app/Controllers/AddressBookController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								app/Controllers/AddressBookController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
 | 
			
		||||
use App\AddressRepository;
 | 
			
		||||
use App\Entity\AddressBookEntry;
 | 
			
		||||
use App\Entity\User;
 | 
			
		||||
use App\Enums\StatusCode;
 | 
			
		||||
use App\Enums\UserAuth;
 | 
			
		||||
use App\Service\Router;
 | 
			
		||||
use App\Service\Template;
 | 
			
		||||
 | 
			
		||||
class AddressBookController
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private readonly Template          $template,
 | 
			
		||||
        private readonly User              $user,
 | 
			
		||||
        private readonly AddressRepository $addressRepository,
 | 
			
		||||
        private readonly Router            $router
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        // empty body
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function main(): never
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->user->getAuth() != UserAuth::AUTH_ANONYMOUS) {
 | 
			
		||||
            $addresses = $this->addressRepository->findAll();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->template->render(templateName: 'index.html.php', vars: [
 | 
			
		||||
            'user'      => $this->user,
 | 
			
		||||
            'router'    => $this->router,
 | 
			
		||||
            'addresses' => $addresses ?? []
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addAddress(): never
 | 
			
		||||
    {
 | 
			
		||||
        if (!empty($_POST)) {
 | 
			
		||||
            $address = new AddressBookEntry(owner: $_POST['owner'], first: $_POST['first'], last: $_POST['last'], street: $_POST['street'], zip: $_POST['zip'], city: $_POST['city'], phone: $_POST['phone']);
 | 
			
		||||
 | 
			
		||||
            if ($this->addressRepository->insert(address: $address)) {
 | 
			
		||||
                $addresses = $this->addressRepository->findAll();
 | 
			
		||||
 | 
			
		||||
                $this->template->render(templateName: 'index.html.php', vars: [
 | 
			
		||||
                    'user'      => $this->user,
 | 
			
		||||
                    'addresses' => $addresses,
 | 
			
		||||
                    'router'    => $this->router
 | 
			
		||||
                ]);
 | 
			
		||||
            } else {
 | 
			
		||||
                die("Error inserting user");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->template->render(templateName: 'addressbook/add_address.html.php', vars: [
 | 
			
		||||
            'user'   => $this->user,
 | 
			
		||||
            'router' => $this->router
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function updateAddress(): void
 | 
			
		||||
    {
 | 
			
		||||
        $_POST = json_decode(json: file_get_contents(filename: "php://input"), associative: true);
 | 
			
		||||
 | 
			
		||||
        if (empty($_POST)) {
 | 
			
		||||
            $this->template->renderJson(results: [
 | 
			
		||||
                                                     'status'  => 400,
 | 
			
		||||
                                                     'message' => 'BAD REQUEST'
 | 
			
		||||
                                                 ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($address = new AddressBookEntry(owner: $_POST['owner'], first: $_POST['first'], last: $_POST['last'], street: $_POST['street'], zip: $_POST['zip'], city: $_POST['city'], phone: $_POST['phone'], id: $_POST['id'])) {
 | 
			
		||||
            if ($this->addressRepository->update(address: $address)) {
 | 
			
		||||
                $status  = 200;
 | 
			
		||||
                $message = 'OK';
 | 
			
		||||
            } else {
 | 
			
		||||
                $status  = 400;
 | 
			
		||||
                $message = 'BAD_REQUEST';
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $status  = 400;
 | 
			
		||||
            $message = "BAD REQUEST";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->template->renderJson(results: [
 | 
			
		||||
                                                 'status'  => $status,
 | 
			
		||||
                                                 'message' => $message
 | 
			
		||||
                                             ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function deleteAddress(): void
 | 
			
		||||
    {
 | 
			
		||||
        $_POST = json_decode(json: file_get_contents(filename: "php://input"), associative: true);
 | 
			
		||||
 | 
			
		||||
        if (empty($_POST)) {
 | 
			
		||||
            $this->template->renderJson(results: [
 | 
			
		||||
                                                     'status'  => 400,
 | 
			
		||||
                                                     'message' => 'BAD REQUEST'
 | 
			
		||||
                                                 ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($address = $this->addressRepository->findByID(id: $_POST['id'])) {
 | 
			
		||||
            if ($this->addressRepository->delete(addressBookEntry: $address)) {
 | 
			
		||||
                $this->template->renderJson(results: [
 | 
			
		||||
                                                         'status'  => 200,
 | 
			
		||||
                                                         'message' => 'OK'
 | 
			
		||||
                                                     ]);
 | 
			
		||||
            } else {
 | 
			
		||||
                $this->template->renderJson(results: [
 | 
			
		||||
                                                         'status'  => 400,
 | 
			
		||||
                                                         'message' => 'BAD REQUEST'
 | 
			
		||||
                                                     ]);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->template->renderJson(results: [
 | 
			
		||||
                                                     'status'  => 400,
 | 
			
		||||
                                                     'message' => 'BAD REQUEST'
 | 
			
		||||
                                                 ]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								app/Models/AddressBookEntry.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								app/Models/AddressBookEntry.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Entity;
 | 
			
		||||
 | 
			
		||||
class AddressBookEntry
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private int    $owner,
 | 
			
		||||
        private string $first,
 | 
			
		||||
        private string $last,
 | 
			
		||||
        private string $street,
 | 
			
		||||
        private string $zip,
 | 
			
		||||
        private string $city,
 | 
			
		||||
        private string $phone,
 | 
			
		||||
        private int    $id = 0,
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        // empty body
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getOwner(): int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->owner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setOwner(int $owner): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->owner = $owner;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStreet(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->street;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStreet(string $street): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->street = $street;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getZip(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->zip;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setZip(string $zip): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->zip = $zip;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getCity(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->city;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setCity(string $city): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->city = $city;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPhone(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->phone;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPhone(string $phone): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->phone = $phone;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getId(): int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setId(int $id): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->id = $id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFirst(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setFirst(string $first): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->first = $first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLast(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLast(string $last): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->last = $last;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										174
									
								
								app/Repositories/AddressRepository.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								app/Repositories/AddressRepository.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Repository;
 | 
			
		||||
 | 
			
		||||
use Mikro24\Service\DatabaseConnection;
 | 
			
		||||
use App\Entity\AddressBookEntry;
 | 
			
		||||
use PDO;
 | 
			
		||||
use PDOException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handles CRUD of Addresses class.
 | 
			
		||||
 */
 | 
			
		||||
class AddressRepository
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(private readonly DatabaseConnection $databaseConnection)
 | 
			
		||||
    {
 | 
			
		||||
        // empty body
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findAll(string $orderBy = 'last'): array
 | 
			
		||||
    {
 | 
			
		||||
        $sql = "
 | 
			
		||||
            SELECT id, owner, first, last, street, zip, city, phone 
 | 
			
		||||
            FROM " . DatabaseConnection::TABLE_ADDRESSES . "
 | 
			
		||||
            ORDER BY :order";
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
 | 
			
		||||
            $statement->bindParam(param: ':order', var: $orderBy);
 | 
			
		||||
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
            $addresses = [];
 | 
			
		||||
            while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
 | 
			
		||||
                $address = new AddressBookEntry(
 | 
			
		||||
                    owner: htmlspecialchars(string: $result['owner']),
 | 
			
		||||
                    first: htmlspecialchars(string: $result['first']),
 | 
			
		||||
                    last: htmlspecialchars(string: $result['last']),
 | 
			
		||||
                    street: htmlspecialchars(string: $result['street']),
 | 
			
		||||
                    zip: htmlspecialchars(string: $result['zip']),
 | 
			
		||||
                    city: htmlspecialchars(string: $result['city']),
 | 
			
		||||
                    phone: htmlspecialchars(string: $result['phone']),
 | 
			
		||||
                    id: htmlspecialchars(string: $result['id']));
 | 
			
		||||
                $addresses[] = $address;
 | 
			
		||||
            }
 | 
			
		||||
            return $addresses;
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            exit($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function findByID(int $id): ?AddressBookEntry
 | 
			
		||||
    {
 | 
			
		||||
        $sql = "
 | 
			
		||||
            SELECT id, owner, first, last, street, zip, city, phone 
 | 
			
		||||
            FROM " . DatabaseConnection::TABLE_ADDRESSES . "
 | 
			
		||||
            WHERE id = :id";
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
 | 
			
		||||
            $statement->bindParam(param: ':id', var: $id);
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
            if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
 | 
			
		||||
                return new AddressBookEntry(
 | 
			
		||||
                    owner: htmlspecialchars(string: $result['owner']),
 | 
			
		||||
                    first: htmlspecialchars(string: $result['first']),
 | 
			
		||||
                    last: htmlspecialchars(string: $result['last']),
 | 
			
		||||
                    street: htmlspecialchars(string: $result['street']),
 | 
			
		||||
                    zip: htmlspecialchars(string: $result['zip']),
 | 
			
		||||
                    city: htmlspecialchars(string: $result['city']),
 | 
			
		||||
                    phone: htmlspecialchars(string: $result['phone']),
 | 
			
		||||
                    id: htmlspecialchars(string: $result['id']));
 | 
			
		||||
            } else {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            exit($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function insert(AddressBookEntry $address): bool|string
 | 
			
		||||
    {
 | 
			
		||||
        $sql = "
 | 
			
		||||
            INSERT INTO " . DatabaseConnection::TABLE_ADDRESSES . " (owner, first, last, city, zip, street, phone)
 | 
			
		||||
            VALUES (:owner, :first, :last, :city, :zip, :street, :phone)";
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $owner = $address->getOwner();
 | 
			
		||||
            $first = $address->getFirst();
 | 
			
		||||
            $last = $address->getLast();
 | 
			
		||||
            $city = $address->getCity();
 | 
			
		||||
            $zip = $address->getZip();
 | 
			
		||||
            $street = $address->getStreet();
 | 
			
		||||
            $phone = $address->getPhone();
 | 
			
		||||
 | 
			
		||||
            $statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
 | 
			
		||||
            $statement->bindParam(param: ':owner', var: $owner);
 | 
			
		||||
            $statement->bindParam(param: ':first', var: $first);
 | 
			
		||||
            $statement->bindParam(param: ':last', var: $last);
 | 
			
		||||
            $statement->bindParam(param: ':city', var: $city);
 | 
			
		||||
            $statement->bindParam(param: ':zip', var: $zip);
 | 
			
		||||
            $statement->bindParam(param: ':street', var: $street);
 | 
			
		||||
            $statement->bindParam(param: ':phone', var: $phone);
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
 | 
			
		||||
            return $this->databaseConnection->getConnection()->lastInsertId();
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            exit($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function update(AddressBookEntry $address): bool|int
 | 
			
		||||
    {
 | 
			
		||||
        $id = $address->getId();
 | 
			
		||||
        $first = $address->getFirst();
 | 
			
		||||
        $last = $address->getLast();
 | 
			
		||||
        $street = $address->getStreet();
 | 
			
		||||
        $zip = $address->getZip();
 | 
			
		||||
        $city = $address->getCity();
 | 
			
		||||
        $phone = $address->getPhone();
 | 
			
		||||
 | 
			
		||||
        $sql = "
 | 
			
		||||
			UPDATE " . DatabaseConnection::TABLE_ADDRESSES . " SET
 | 
			
		||||
				first = :first,
 | 
			
		||||
				last = :last,
 | 
			
		||||
				street = :street,
 | 
			
		||||
				zip = :zip,
 | 
			
		||||
				city = :city,
 | 
			
		||||
				phone = :phone
 | 
			
		||||
            WHERE id = :id";
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
 | 
			
		||||
            $statement->bindParam(param: 'id', var: $id);
 | 
			
		||||
            $statement->bindParam(param: 'first', var: $first);
 | 
			
		||||
            $statement->bindParam(param: 'last', var: $last);
 | 
			
		||||
            $statement->bindParam(param: 'street', var: $street);
 | 
			
		||||
            $statement->bindParam(param: 'zip', var: $zip);
 | 
			
		||||
            $statement->bindParam(param: 'city', var: $city);
 | 
			
		||||
            $statement->bindParam(param: 'phone', var: $phone);
 | 
			
		||||
            return $statement->execute();
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            echo $e->getMessage();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function delete(AddressBookEntry $addressBookEntry): int
 | 
			
		||||
    {
 | 
			
		||||
        $sql = "
 | 
			
		||||
            DELETE FROM " . DatabaseConnection::TABLE_ADDRESSES . "
 | 
			
		||||
            WHERE id = :id";
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
 | 
			
		||||
            $id = $addressBookEntry->getId();
 | 
			
		||||
            $statement->bindParam(param: 'id', var: $id);
 | 
			
		||||
            return $statement->execute();
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            exit($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										206
									
								
								public/assets/js/functions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								public/assets/js/functions.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,206 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
function addAddress(url) {
 | 
			
		||||
    location.href = url
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function editAddress(id) {
 | 
			
		||||
    if (document.getElementById('edit_button_' + id).value === 'Save') {
 | 
			
		||||
        // save
 | 
			
		||||
        const url = "/address/update";
 | 
			
		||||
        fetch(url, {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            body: JSON.stringify({
 | 
			
		||||
                id: id,
 | 
			
		||||
                owner: document.getElementById('owner_' + id).value,
 | 
			
		||||
                first: document.getElementById('first_' + id).value,
 | 
			
		||||
                last: document.getElementById('last_' + id).value,
 | 
			
		||||
                street: document.getElementById('street_' + id).value,
 | 
			
		||||
                zip: document.getElementById('zip_' + id).value,
 | 
			
		||||
                city: document.getElementById('city_' + id).value,
 | 
			
		||||
                phone: document.getElementById('phone_' + id).value,
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
            .then(
 | 
			
		||||
                response => response.text()
 | 
			
		||||
            ).then(
 | 
			
		||||
            json => {
 | 
			
		||||
                let jsonObject = JSON.parse(json)
 | 
			
		||||
                if (jsonObject.status === 200) {
 | 
			
		||||
                    setInfo('Data successfully saved.')
 | 
			
		||||
                } else {
 | 
			
		||||
                    setError(jsonObject.message);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        document.getElementById('first_' + id).disabled = true
 | 
			
		||||
        document.getElementById('last_' + id).disabled = true
 | 
			
		||||
        document.getElementById('street_' + id).disabled = true
 | 
			
		||||
        document.getElementById('zip_' + id).disabled = true
 | 
			
		||||
        document.getElementById('city_' + id).disabled = true
 | 
			
		||||
        document.getElementById('phone_' + id).disabled = true
 | 
			
		||||
 | 
			
		||||
        document.getElementById('edit_button_' + id).value = 'Edit'
 | 
			
		||||
    } else {
 | 
			
		||||
        //switch to edit
 | 
			
		||||
        document.getElementById('first_' + id).disabled = false
 | 
			
		||||
        document.getElementById('last_' + id).disabled = false
 | 
			
		||||
        document.getElementById('street_' + id).disabled = false
 | 
			
		||||
        document.getElementById('zip_' + id).disabled = false
 | 
			
		||||
        document.getElementById('city_' + id).disabled = false
 | 
			
		||||
        document.getElementById('phone_' + id).disabled = false
 | 
			
		||||
 | 
			
		||||
        document.getElementById('edit_button_' + id).value = 'Save'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deleteAddress(id) {
 | 
			
		||||
    if (confirm('Are you sure?')) {
 | 
			
		||||
        const url = "/address/delete";
 | 
			
		||||
        fetch(url, {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            body: JSON.stringify({
 | 
			
		||||
                id: id
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
            .then(
 | 
			
		||||
                response => response.text()
 | 
			
		||||
            ).then(
 | 
			
		||||
            json => {
 | 
			
		||||
                let jsonObject = JSON.parse(json)
 | 
			
		||||
                if (jsonObject.status === 200) {
 | 
			
		||||
                    setInfo('Data successfully saved.')
 | 
			
		||||
                } else {
 | 
			
		||||
                    setError(jsonObject.message);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        let row = document.getElementById('row_' + id)
 | 
			
		||||
        row.parentNode.removeChild(row)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function upCase(text) {
 | 
			
		||||
    return text[0].toUpperCase() + text.substring(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sortBy(column) {
 | 
			
		||||
    // clear titles
 | 
			
		||||
    const titles = ['first', 'last', 'street', 'zip', 'city', 'phone']
 | 
			
		||||
    titles.forEach((title) =>
 | 
			
		||||
        document.getElementById(title).innerHTML = upCase(title)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    console.log("col", column)
 | 
			
		||||
    console.log("curcol", currentColumn)
 | 
			
		||||
 | 
			
		||||
    if (currentColumn === column) {
 | 
			
		||||
        console.log("in switch")
 | 
			
		||||
        // switch direction on every call on same column
 | 
			
		||||
        if (currentSortOrder === 'asc') {
 | 
			
		||||
            currentSortOrder = 'desc'
 | 
			
		||||
        } else {
 | 
			
		||||
            currentSortOrder = 'asc'
 | 
			
		||||
        }
 | 
			
		||||
        console.log("col", column)
 | 
			
		||||
    } else {
 | 
			
		||||
        currentColumn = column
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let currentTitleElement = document.getElementById(column)
 | 
			
		||||
    let currentTitle = currentTitleElement.innerHTML
 | 
			
		||||
    let newTitle
 | 
			
		||||
 | 
			
		||||
    if (currentSortOrder === 'asc') {
 | 
			
		||||
        newTitle = currentTitle[0] + currentTitle.substring(1) + ' ⬇'
 | 
			
		||||
    } else {
 | 
			
		||||
        newTitle = currentTitle[0] + currentTitle.substring(1) + ' ⬆'
 | 
			
		||||
    }
 | 
			
		||||
    currentTitleElement.innerHTML = newTitle
 | 
			
		||||
 | 
			
		||||
    const table = document.getElementById('address_table');
 | 
			
		||||
    let dirty = true;
 | 
			
		||||
    // loop until clean
 | 
			
		||||
    while (dirty) {
 | 
			
		||||
        // assume we are finished
 | 
			
		||||
        dirty = false
 | 
			
		||||
        const rows = table.rows;
 | 
			
		||||
        for (let i = 1; i < (rows.length - 2); i++) {
 | 
			
		||||
            let x = rows[i]
 | 
			
		||||
            let rowXId = x.id
 | 
			
		||||
            let rowXNumber = rowXId.match(/\d+/)
 | 
			
		||||
            let valueX = document.getElementById(column + '_' + rowXNumber).value
 | 
			
		||||
 | 
			
		||||
            let y = rows[i + 1]
 | 
			
		||||
            let rowYId = y.id
 | 
			
		||||
            let rowYNumber = rowYId.match(/\d+/)
 | 
			
		||||
            let valueY = document.getElementById(column + '_' + rowYNumber).value
 | 
			
		||||
 | 
			
		||||
            let sortOrder
 | 
			
		||||
            if (currentSortOrder === 'asc') {
 | 
			
		||||
                sortOrder = 1
 | 
			
		||||
            } else {
 | 
			
		||||
                sortOrder = -1
 | 
			
		||||
            }
 | 
			
		||||
            if (valueX.localeCompare(valueY) === sortOrder) {
 | 
			
		||||
                x.parentNode.insertBefore(y, x);
 | 
			
		||||
                dirty = true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function setInfo(info) {
 | 
			
		||||
    const infoBox = document.getElementById('info_box')
 | 
			
		||||
    infoBox.innerHTML = info
 | 
			
		||||
    infoBox.style.display = 'block'
 | 
			
		||||
    infoBox.classList.add('panel_float')
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
        infoBox.style.display = 'none'
 | 
			
		||||
    }, 2500)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setError(error) {
 | 
			
		||||
    const errorBox = document.getElementById('error_box')
 | 
			
		||||
    const errorText = document.getElementById('error_text')
 | 
			
		||||
    const infoButton = document.getElementById('info_button')
 | 
			
		||||
    if (errorBox.style.display === 'block') {
 | 
			
		||||
        errorBox.style.display = 'none'
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    if (infoButton != null) {
 | 
			
		||||
        infoButton.disabled = true
 | 
			
		||||
    }
 | 
			
		||||
    errorText.innerHTML = error
 | 
			
		||||
    errorBox.style.display = 'block'
 | 
			
		||||
    errorBox.classList.add('panel_float')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function closeError() {
 | 
			
		||||
    const errorBox = document.getElementById('error_box')
 | 
			
		||||
    const infoButton = document.getElementById('info_button')
 | 
			
		||||
    if (infoButton) {
 | 
			
		||||
        infoButton.disabled = false
 | 
			
		||||
    }
 | 
			
		||||
    errorBox.style.display = 'none'
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// global scope
 | 
			
		||||
let currentSortOrder = 'desc'
 | 
			
		||||
let currentColumn = 'last'
 | 
			
		||||
 | 
			
		||||
document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
    const table = document.getElementById('address_table') || false
 | 
			
		||||
    if (table) {
 | 
			
		||||
        sortBy('last')
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
@@ -27,3 +27,101 @@ a:active {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table, th, td {
 | 
			
		||||
    border: 1px solid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
label {
 | 
			
		||||
    display: block;
 | 
			
		||||
    padding: 1ex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.panel_float {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    z-index: 2400;
 | 
			
		||||
    opacity: 0.70;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
    top: 110px !important;
 | 
			
		||||
    -webkit-transition: all 0.5s ease-in-out;
 | 
			
		||||
    -moz-transition: all 0.5s ease-in-out;
 | 
			
		||||
    -ms-transition: all 0.5s ease-in-out;
 | 
			
		||||
    -o-transition: all 0.5s ease-in-out;
 | 
			
		||||
    transition: all 0.5s ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#info_box {
 | 
			
		||||
    background-color: #3fc52a;
 | 
			
		||||
    border: solid #cdcdcd;
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    color: #1f1f1f;
 | 
			
		||||
    display: none;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
    width: 50%;
 | 
			
		||||
    margin-left: 200px;
 | 
			
		||||
    margin-right: 200px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info_button {
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    border: solid #cdcdcd;
 | 
			
		||||
    color: #1f1f1f;
 | 
			
		||||
    padding: 8px 32px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    margin: 4px 2px;
 | 
			
		||||
    background-color: #3fc52a;
 | 
			
		||||
    transition-duration: 0.4s;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#error_box {
 | 
			
		||||
    background-color: #e06844;
 | 
			
		||||
    border: solid #cdcdcd;
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    color: #1f1f1f;
 | 
			
		||||
    display: none;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 10;
 | 
			
		||||
    width: 50%;
 | 
			
		||||
    margin-left: 200px;
 | 
			
		||||
    margin-right: 200px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.error_button {
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    border: solid #cdcdcd;
 | 
			
		||||
    color: #1f1f1f;
 | 
			
		||||
    padding: 8px 32px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    margin: 4px 2px;
 | 
			
		||||
    background-color: #e06844;
 | 
			
		||||
    transition-duration: 0.4s;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.close_button {
 | 
			
		||||
    margin-left: 15px;
 | 
			
		||||
    color: white;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    float: right;
 | 
			
		||||
    font-size: 22px;
 | 
			
		||||
    line-height: 20px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    transition: 0.3s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.close_button:hover {
 | 
			
		||||
    color: black;
 | 
			
		||||
}
 | 
			
		||||
@@ -12,6 +12,11 @@ ini_set(option: 'display_startup_errors', value: 1);
 | 
			
		||||
// no one sane should ignore deprecations
 | 
			
		||||
error_reporting(error_level: E_ALL);
 | 
			
		||||
 | 
			
		||||
// just during dev
 | 
			
		||||
opcache_reset();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
session_start();
 | 
			
		||||
 | 
			
		||||
require dirname(path: __DIR__) . '/src/bootstrap.php';
 | 
			
		||||
@@ -28,10 +33,6 @@ $security         = $container->get(className: SecurityController::class);
 | 
			
		||||
$addressBook      = $container->get(className: AddressBookController::class);
 | 
			
		||||
$addressBookAdmin = $container->get(className: AddressBookAdminController::class);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// TODO maybe refactor route adding to the controllers?
 | 
			
		||||
// I currently think that makes sense.
 | 
			
		||||
 | 
			
		||||
$router->addRoute(name: 'app_login', route: '/login', callback: function () use ($security) {
 | 
			
		||||
    $security->login();
 | 
			
		||||
});
 | 
			
		||||
@@ -64,5 +65,16 @@ $router->addRoute(name: 'app_admin_users_delete', route: '/admin/users/delete/{n
 | 
			
		||||
    $addressBookAdmin->adminUserDelete(parameters: $parameters);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$router->addRoute(name: 'address_add', route: '/address/add', callback: function () use ($addressBook) {
 | 
			
		||||
    $addressBook->addAddress();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$router->addRoute(name: 'address_add', route: '/address/update', callback: function () use ($addressBook) {
 | 
			
		||||
    $addressBook->updateAddress();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$router->addRoute(name: 'address_add', route: '/address/delete', callback: function () use ($addressBook) {
 | 
			
		||||
    $addressBook->deleteAddress();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$router->handleRouting();
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
 | 
			
		||||
use App\Service\Template;
 | 
			
		||||
 | 
			
		||||
class AddressBook
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(private readonly Template $template)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function main(): void
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->template->render(templateName: 'index.tpl');
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            die($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    public function admin(string $command = '')
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->template->render(templateName: 'admin/index.tpl');
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            die($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function login()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->template->render(templateName: 'admin/index.tpl');
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
            die($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
 | 
			
		||||
use App\Entity\User;
 | 
			
		||||
use App\Service\Router;
 | 
			
		||||
use App\Service\Template;
 | 
			
		||||
use App\Repository\UserRepository;
 | 
			
		||||
use JetBrains\PhpStorm\NoReturn;
 | 
			
		||||
 | 
			
		||||
class AddressBookController
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private readonly Template       $template,
 | 
			
		||||
        private readonly User           $user,
 | 
			
		||||
        private readonly UserRepository $userRepository,
 | 
			
		||||
        private readonly Router         $router
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        // empty body
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[NoReturn]
 | 
			
		||||
    public function main(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->template->render(templateName: 'index.html.php', vars: [
 | 
			
		||||
            'user' => $this->user,
 | 
			
		||||
            'router' => $this->router
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Controller;
 | 
			
		||||
namespace App\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\Entity\User;
 | 
			
		||||
use App\Repository\UserRepository;
 | 
			
		||||
@@ -32,6 +32,7 @@ class SecurityController
 | 
			
		||||
            $password = $_POST['password'] ?? '';
 | 
			
		||||
 | 
			
		||||
            if ($nick && $password) {
 | 
			
		||||
                $nick = strtolower(string: $nick);
 | 
			
		||||
                if ($user = $this->userRepository->findbyNick(nick: $nick)) {
 | 
			
		||||
                    if (password_verify(password: $password, hash: $user->getPassword())) {
 | 
			
		||||
                        $_SESSION['user_id'] = $user->getId();
 | 
			
		||||
@@ -1,63 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2022. Micha Espey <tracer@24unix.net>
 | 
			
		||||
 *
 | 
			
		||||
 * For the full copyright and license information, please view the LICENSE
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Entity;
 | 
			
		||||
 | 
			
		||||
class AddressBookEntry
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private int $userid,
 | 
			
		||||
        private string $first,
 | 
			
		||||
        private string $last,
 | 
			
		||||
        private string $nick,
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        // empty body
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getUserid(): int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->userid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setUserid(int $userid): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->userid = $userid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFirst(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setFirst(string $first): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->first = $first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLast(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLast(string $last): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->last = $last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getNick(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->nick;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setNick(string $nick): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->nick = $nick;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -7,10 +7,10 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Repository;
 | 
			
		||||
namespace Mikro24\Repositories;
 | 
			
		||||
 | 
			
		||||
use App\Service\DatabaseConnection;
 | 
			
		||||
use App\Entity\User;
 | 
			
		||||
use Mikro24\Service\DatabaseConnection;
 | 
			
		||||
use Mikro24\Models\User;
 | 
			
		||||
use PDO;
 | 
			
		||||
use PDOException;
 | 
			
		||||
 | 
			
		||||
@@ -38,7 +38,13 @@ class UserRepository
 | 
			
		||||
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
            while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
 | 
			
		||||
                $user = new User(nick: $result['nick'], password: $result['password'], first: $result['first'], last: $result['last'], id: $result['id'], isAdmin: $result['is_admin']);
 | 
			
		||||
                $user = new User(
 | 
			
		||||
                    nick: htmlspecialchars(string: $result['nick']),
 | 
			
		||||
                    password: $result['password'],
 | 
			
		||||
                    first: htmlspecialchars(string: $result['first']),
 | 
			
		||||
                    last: htmlspecialchars(string: $result['last']),
 | 
			
		||||
                    id: $result['id'],
 | 
			
		||||
                    isAdmin: $result['is_admin']);
 | 
			
		||||
                $users[] = $user;
 | 
			
		||||
            }
 | 
			
		||||
            return $users;
 | 
			
		||||
@@ -60,7 +66,13 @@ class UserRepository
 | 
			
		||||
            $statement->bindParam(param: ':id', var: $id);
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
            if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
 | 
			
		||||
                return new User(nick: $result['nick'], password: $result['password'], first: $result['first'], last: $result['last'], id: $result['id'], isAdmin: $result['is_admin']);
 | 
			
		||||
                return new User(
 | 
			
		||||
                    nick: htmlspecialchars(string: $result['nick']),
 | 
			
		||||
                    password: $result['password'],
 | 
			
		||||
                    first: htmlspecialchars(string: $result['first']),
 | 
			
		||||
                    last: htmlspecialchars(string: $result['last']),
 | 
			
		||||
                    id: $result['id'],
 | 
			
		||||
                    isAdmin: $result['is_admin']);
 | 
			
		||||
            } else {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
@@ -71,6 +83,8 @@ class UserRepository
 | 
			
		||||
 | 
			
		||||
    public function findByNick(string $nick): ?User
 | 
			
		||||
    {
 | 
			
		||||
        $nick = strtolower(string: $nick);
 | 
			
		||||
 | 
			
		||||
        $sql = "
 | 
			
		||||
            SELECT id, nick, password, first, last, is_admin
 | 
			
		||||
            FROM " . DatabaseConnection::TABLE_USERS . "
 | 
			
		||||
@@ -81,7 +95,13 @@ class UserRepository
 | 
			
		||||
            $statement->bindParam(param: ':nick', var: $nick);
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
            if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
 | 
			
		||||
                return new User(nick: $result['nick'], password: $result['password'], first: $result['first'], last: $result['last'], id: $result['id'], isAdmin: $result['is_admin']);
 | 
			
		||||
                return new User(
 | 
			
		||||
                    nick: htmlspecialchars(string: $result['nick']),
 | 
			
		||||
                    password: $result['password'],
 | 
			
		||||
                    first: htmlspecialchars(string: $result['first']),
 | 
			
		||||
                    last: htmlspecialchars(string: $result['last']),
 | 
			
		||||
                    id: $result['id'],
 | 
			
		||||
                    isAdmin: $result['is_admin']);
 | 
			
		||||
            } else {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
@@ -117,7 +137,7 @@ class UserRepository
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function update(User $user): bool|int
 | 
			
		||||
    public function update(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        $id = $user->getId();
 | 
			
		||||
        $nick = $user->getNick();
 | 
			
		||||
@@ -149,9 +169,7 @@ class UserRepository
 | 
			
		||||
            $statement->bindParam(param: 'first', var: $first);
 | 
			
		||||
            $statement->bindParam(param: 'last', var: $last);
 | 
			
		||||
            $statement->bindParam(param: 'is_admin', var: $isAdmin);
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
 | 
			
		||||
            return $statement->rowCount();
 | 
			
		||||
            return $statement->execute();
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            echo $e->getMessage();
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -159,7 +177,7 @@ class UserRepository
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function delete(User $user): int
 | 
			
		||||
    public function delete(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        $sql = "
 | 
			
		||||
            DELETE FROM " . DatabaseConnection::TABLE_USERS . "
 | 
			
		||||
@@ -169,9 +187,7 @@ class UserRepository
 | 
			
		||||
            $statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
 | 
			
		||||
            $id = $user->getId();
 | 
			
		||||
            $statement->bindParam(param: 'id', var: $id);
 | 
			
		||||
            $statement->execute();
 | 
			
		||||
 | 
			
		||||
            return $statement->rowCount();
 | 
			
		||||
            return $statement->execute();
 | 
			
		||||
        } catch (PDOException $e) {
 | 
			
		||||
            exit($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
@@ -7,9 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Service;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
namespace Mikro24\Services;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
@@ -21,7 +19,7 @@ class Config
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        // Check for either config.json.local or config.json.
 | 
			
		||||
        $configFile = dirname(path: __DIR__, levels: 2) . "/config.json.local";
 | 
			
		||||
        $configFile = dirname(path: __DIR__, levels: 2) . "/config.local.json";
 | 
			
		||||
        if (!file_exists(filename: $configFile)) {
 | 
			
		||||
            $configFile = dirname(path: __DIR__, levels: 2) . "/config.json";
 | 
			
		||||
        }
 | 
			
		||||
@@ -7,13 +7,14 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Service;
 | 
			
		||||
namespace Mikro24\Services;
 | 
			
		||||
 | 
			
		||||
use App\Controller\AddressBookAdminController;
 | 
			
		||||
use App\Controller\AddressBookController;
 | 
			
		||||
use App\Controller\SecurityController;
 | 
			
		||||
use App\Entity\User;
 | 
			
		||||
use App\Repository\UserRepository;
 | 
			
		||||
use Mikro24\Controllers\SecurityController;
 | 
			
		||||
use Mikro24\Models\User;
 | 
			
		||||
use Mikro24\Repositories\UserRepository;
 | 
			
		||||
use App\Controllers\AddressBookAdminController;
 | 
			
		||||
use App\Controllers\AddressBookController;
 | 
			
		||||
use App\Repositories\AddressRepository;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A quick and dirty class container for DI.
 | 
			
		||||
@@ -26,6 +27,7 @@ class Container
 | 
			
		||||
 | 
			
		||||
    private AddressBookController      $addressBook;
 | 
			
		||||
    private AddressBookAdminController $addressBookAdmin;
 | 
			
		||||
    private AddressRepository          $addressRepository;
 | 
			
		||||
    private Config                     $config;
 | 
			
		||||
    private DatabaseConnection         $databaseConnection;
 | 
			
		||||
    private Router                     $router;
 | 
			
		||||
@@ -41,23 +43,24 @@ class Container
 | 
			
		||||
        $this->template           = new Template(templateDir: dirname(path: __DIR__, levels: 2) . '/templates/');
 | 
			
		||||
        $this->router             = new Router(template: $this->template);
 | 
			
		||||
        $this->userRepository     = new UserRepository(databaseConnection: $this->databaseConnection);
 | 
			
		||||
        $this->addressRepository  = new AddressRepository(databaseConnection: $this->databaseConnection);
 | 
			
		||||
        $this->securityController = new SecurityController(template: $this->template, userRepository: $this->userRepository, router: $this->router);
 | 
			
		||||
        if (empty($_SESSION['user_id'])) {
 | 
			
		||||
            $this->user = new User(); // ANONYMOUS
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->user = $this->userRepository->findByID(id: $_SESSION['user_id']);
 | 
			
		||||
        }
 | 
			
		||||
        $this->addressBook      = new AddressBookController(template: $this->template, user: $this->user, userRepository: $this->userRepository, router: $this->router);
 | 
			
		||||
        $this->addressBook      = new AddressBookController(template: $this->template, user: $this->user, addressRepository: $this->addressRepository, router: $this->router);
 | 
			
		||||
        $this->addressBookAdmin = new AddressBookAdminController(template: $this->template, user: $this->user, userRepository: $this->userRepository, router: $this->router);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function get(string $className): object
 | 
			
		||||
    {
 | 
			
		||||
        return match ($className) {
 | 
			
		||||
            'App\Controller\AddressBookController' => $this->addressBook,
 | 
			
		||||
            'App\Controller\AddressBookAdminController' => $this->addressBookAdmin,
 | 
			
		||||
            'App\Controller\SecurityController' => $this->securityController,
 | 
			
		||||
            'App\Service\Router' => $this->router,
 | 
			
		||||
            'App\Controllers\AddressBookController' => $this->addressBook,
 | 
			
		||||
            'App\Controllers\AddressBookAdminController' => $this->addressBookAdmin,
 | 
			
		||||
            'Mikro24\Controllers\SecurityController' => $this->securityController,
 | 
			
		||||
            'Mikro24\Service\Router' => $this->router,
 | 
			
		||||
            //default => throw new Exception(message: "Missing class definition: $class")
 | 
			
		||||
            default => die("Missing class definition: $className")
 | 
			
		||||
        };
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Service;
 | 
			
		||||
namespace Mikro24\Services;
 | 
			
		||||
 | 
			
		||||
use PDO;
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +36,7 @@ class DatabaseConnection
 | 
			
		||||
            username: $dbUser,
 | 
			
		||||
            password: $dbPassword
 | 
			
		||||
        );
 | 
			
		||||
        $this->dbConnection->setAttribute(attribute: PDO::ATTR_ERRMODE, value: PDO::ERRMODE_EXCEPTION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getConnection(): PDO
 | 
			
		||||
@@ -7,10 +7,10 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Service;
 | 
			
		||||
namespace Mikro24\Services;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
use App\Entity\Route;
 | 
			
		||||
use Mikro24\Models\Route;
 | 
			
		||||
use Closure;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -35,7 +35,7 @@ class Router
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * This method takes a route like /admin/users/{user} and creates a regex to match on call
 | 
			
		||||
     * More complex routes as /posts/{thread}/show/{page} are supported as well.
 | 
			
		||||
     * More complex routes like /posts/{thread}/show/{page} are supported as well.
 | 
			
		||||
     */
 | 
			
		||||
    function addRoute(string $name, string $route, Closure $callback): void
 | 
			
		||||
    {
 | 
			
		||||
@@ -45,6 +45,7 @@ class Router
 | 
			
		||||
 | 
			
		||||
        // create regex for route:
 | 
			
		||||
        $regex = preg_replace(pattern: '/{.+?}/', replacement: '([a-zA-Z0-9]*)', subject: $route);
 | 
			
		||||
        // escape \ in regex
 | 
			
		||||
        $regex = '/^' . str_replace(search: "/", replace: '\\/', subject: $regex) . '$/i';
 | 
			
		||||
 | 
			
		||||
        $route = new Route(name: $name, route: $route, regEx: $regex, parameters: $parameters, callback: $callback);
 | 
			
		||||
@@ -64,7 +65,7 @@ class Router
 | 
			
		||||
        $requestUri = $_SERVER['REQUEST_URI'];
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Static routes have preference over dynamic ones, so
 | 
			
		||||
         * Static routes have precedence over dynamic ones, so
 | 
			
		||||
         * /admin/user/add to add and
 | 
			
		||||
         * /admin/user/{name} to edit is possible.
 | 
			
		||||
         * A user named "add" of course not :)
 | 
			
		||||
@@ -82,6 +83,8 @@ class Router
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($this->dynamicRoutes as $route) {
 | 
			
		||||
            // PHPStorm doesn't know that $parameters are always available,
 | 
			
		||||
            // (as these are dynamic routes) so I init the array just to make PHPStorm happy.
 | 
			
		||||
            $parameters = [];
 | 
			
		||||
            if (preg_match(pattern: $route->getRegex(), subject: $requestUri, matches: $matches)) {
 | 
			
		||||
                foreach ($route->getParameters() as $id => $parameter) {
 | 
			
		||||
@@ -101,10 +104,9 @@ class Router
 | 
			
		||||
    public function path(string $routeName, array $vars = [])
 | 
			
		||||
    {
 | 
			
		||||
        foreach (array_merge($this->dynamicRoutes, $this->staticRoutes) as $route) {
 | 
			
		||||
 | 
			
		||||
            if ($route->getName() == $routeName) {
 | 
			
		||||
                if ($vars) {
 | 
			
		||||
                    // build route
 | 
			
		||||
                    // build route for dynamic routes
 | 
			
		||||
                    $route = $route->getRoute();
 | 
			
		||||
                    // replace placeholder with current values
 | 
			
		||||
                    foreach ($vars as $key => $value) {
 | 
			
		||||
@@ -116,7 +118,7 @@ class Router
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // no 404, this is reached only if the code is wrong
 | 
			
		||||
        // no 404, this is reached only if the code is buggy
 | 
			
		||||
        die("Missing Route: $routeName");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,15 +6,13 @@
 | 
			
		||||
 * file that was distributed with this source code.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Service;
 | 
			
		||||
namespace Mikro24\Services;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * As I'm not allowed to use 3rd party code like Twig or Smarty I ended up
 | 
			
		||||
 * using PHP as a templating engine.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use JetBrains\PhpStorm\NoReturn;
 | 
			
		||||
 | 
			
		||||
class Template
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
@@ -28,8 +26,7 @@ class Template
 | 
			
		||||
    /*
 | 
			
		||||
     * Add variables to template and throw it out
 | 
			
		||||
     */
 | 
			
		||||
    #[NoReturn]
 | 
			
		||||
    public function render(string $templateName, array $vars = []): void
 | 
			
		||||
    public function render(string $templateName, array $vars = []): never
 | 
			
		||||
    {
 | 
			
		||||
        // assign template vars
 | 
			
		||||
        foreach ($vars as $name => $value) {
 | 
			
		||||
@@ -44,4 +41,14 @@ class Template
 | 
			
		||||
        }
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * For AJAX calls, return json
 | 
			
		||||
     */
 | 
			
		||||
    public function renderJson(array $results): never
 | 
			
		||||
    {
 | 
			
		||||
        http_response_code(response_code: $results['status']);
 | 
			
		||||
        echo json_encode(value: $results);
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,7 @@
 | 
			
		||||
    <!-- mind the javascript -->
 | 
			
		||||
    <script src="/assets/js/functions.js"></script>
 | 
			
		||||
    <?php if (!empty($message)): ?>
 | 
			
		||||
        <script>setError('<?= $message ?>')</script>
 | 
			
		||||
    <?php endif; ?>
 | 
			
		||||
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -1,32 +1,27 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
    <head>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>Address Book
 | 
			
		||||
            <?php if (!empty($user)): ?>
 | 
			
		||||
        <?php if (!empty($user->getNick())): ?>
 | 
			
		||||
             - <?= $user->getNick() ?>
 | 
			
		||||
        <?php endif; ?>
 | 
			
		||||
 | 
			
		||||
    </title>
 | 
			
		||||
    <link rel="stylesheet" href="/assets/styles/main.css">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
    <h1>Address Book</h1>
 | 
			
		||||
    <a href="<?= $router->path('app_main'); ?>">🏠 Home</a>
 | 
			
		||||
    <a href="<?= $router->path('app_admin'); ?>">⚙ Admin</a>
 | 
			
		||||
    <?php if (empty($user) || $user->getAuth() == \App\Enums\UserAuth::AUTH_ANONYMOUS): ?>
 | 
			
		||||
        <a href="/login">🚪Login</a>
 | 
			
		||||
    <?php else: ?>
 | 
			
		||||
        <a href="/logout">🚪Logout</a>
 | 
			
		||||
    <?php endif; ?>
 | 
			
		||||
    <?php
 | 
			
		||||
        if ($user->getAuth() == \App\Enums\UserAuth::AUTH_ANONYMOUS) {
 | 
			
		||||
            echo "no";
 | 
			
		||||
        } else {
 | 
			
		||||
            echo "yes";
 | 
			
		||||
        }
 | 
			
		||||
        ?>
 | 
			
		||||
    <?php if (!empty($user) && !$user->getAuth() == \App\Enums\UserAuth::AUTH_ANONYMOUS): ?>
 | 
			
		||||
        <br>
 | 
			
		||||
        Welcome back, <?= $user->getNick(); ?>
 | 
			
		||||
    <?php endif; ?>
 | 
			
		||||
<h1>Address Book</h1>
 | 
			
		||||
<a href="<?= $router->path('app_main'); ?>">⌂ Home</a>
 | 
			
		||||
<a href="<?= $router->path('app_admin'); ?>">⚙ Admin</a>
 | 
			
		||||
<?php if (empty($user) || $user->getAuth() == \App\Enums\UserAuth::AUTH_ANONYMOUS): ?>
 | 
			
		||||
    <a href="<?= $router->path('app_login'); ?>">⎆ Login</a>
 | 
			
		||||
<?php else: ?>
 | 
			
		||||
    <a href="<?= $router->path('app_logout'); ?>">⎋ Logout</a>
 | 
			
		||||
<?php endif; ?>
 | 
			
		||||
<br>
 | 
			
		||||
<div id="info_box">Info</div>
 | 
			
		||||
<div id="error_box">
 | 
			
		||||
    <span class="close_button" onclick="closeError()">×</span>
 | 
			
		||||
    <div id="error_text"></div>
 | 
			
		||||
</div>
 | 
			
		||||
<br>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <title>Address Book</title>
 | 
			
		||||
        <link rel="stylesheet" href="/assets/styles/main.css">
 | 
			
		||||
    </head>
 | 
			
		||||
							
								
								
									
										35
									
								
								templates/addressbook/add_address.html.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								templates/addressbook/add_address.html.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
<?php include dirname(path: __DIR__) . '/_header.html.php'; ?>
 | 
			
		||||
 | 
			
		||||
<form method="POST">
 | 
			
		||||
    <input type="hidden" name="owner" id="owner" value="<?= $user->getId() ?>">
 | 
			
		||||
 | 
			
		||||
    <label for="first">First</label>
 | 
			
		||||
    <input type="text" name="first" id="first" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="last">Last</label>
 | 
			
		||||
    <input type="text" name="last" id="last" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="city">City</label>
 | 
			
		||||
    <input type="text" name="city" id="city">
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="zip">Zip</label>
 | 
			
		||||
    <input type="text" name="zip" id="zip">
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="street">Street</label>
 | 
			
		||||
    <input type="text" name="street" id="street">
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="phone">Phone</label>
 | 
			
		||||
    <input type="text" name="phone" id="phone">
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <!-- maybe later -->
 | 
			
		||||
    <!-- <input type="hidden" name="_csrf" value="csrf_token" -->
 | 
			
		||||
    <input type="submit" value="Save">
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
<?php include dirname(path: __DIR__) . '/_footer.html.php' ?>
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
<?php include dirname(path: __DIR__) . '/_header.html.php'; ?>
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
<h1>Address Book - Admin</h1>
 | 
			
		||||
<a href="<?= $router->path('app_admin_users') ?>">👱Users</a>
 | 
			
		||||
<a href="<?= $router->path('app_admin_users'); ?>">👱 Users</a>
 | 
			
		||||
 | 
			
		||||
<?php include dirname(path: __DIR__) . '/_footer.html.php' ?>
 | 
			
		||||
 | 
			
		||||
<button type="button" class="info_button" id="info_button" onclick="setInfo('Test Info - auto hide')">Info</button>
 | 
			
		||||
<button type="button" class="error_button" onclick="setError('Test Error - must be closed manually')">Error</button>
 | 
			
		||||
@@ -2,19 +2,19 @@
 | 
			
		||||
 | 
			
		||||
<form method="POST">
 | 
			
		||||
    <label for="nick">Username</label>
 | 
			
		||||
    <input type="text" name="nick" id="nick" required>
 | 
			
		||||
    <input type="text" name="nick" id="nick" maxlength="20" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="new_password">Password</label>
 | 
			
		||||
    <input type="password" name="new_password" id="new_password" required>
 | 
			
		||||
    <input type="password" name="new_password" id="new_password" maxlength="40" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="first">First</label>
 | 
			
		||||
    <input type="text" name="first" id="first" required>
 | 
			
		||||
    <input type="text" name="first" id="first" maxlength="40" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="last">Last</label>
 | 
			
		||||
    <input type="text" name="last" id="last" required>
 | 
			
		||||
    <input type="text" name="last" id="last" maxlength="40" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="is_admin">Is Admin</label>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,19 +4,19 @@
 | 
			
		||||
    <input type="hidden" name="id" value="<?= $editUser->getId() ?>">
 | 
			
		||||
 | 
			
		||||
    <label for="nick">Username</label>
 | 
			
		||||
    <input type="text" name="nick" id="nick" value="<?= $editUser->getNick() ?>" required>
 | 
			
		||||
    <input type="text" name="nick" id="nick" value="<?= $editUser->getNick() ?>" maxlength="20" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="new_password">Password (leave empty to keep the current one)</label>
 | 
			
		||||
    <input type="password" name="new_password" id="new_password">
 | 
			
		||||
    <input type="password" name="new_password" id="new_password" maxlength="40">
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="first">First</label>
 | 
			
		||||
    <input type="text" name="first" id="first" value="<?= $editUser->getFirst() ?>" required>
 | 
			
		||||
    <input type="text" name="first" id="first" value="<?= $editUser->getFirst() ?>" maxlength="40" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="last">Last</label>
 | 
			
		||||
    <input type="text" name="last" id="last" value="<?= $editUser->getLast() ?>" required>
 | 
			
		||||
    <input type="text" name="last" id="last" value="<?= $editUser->getLast() ?>" maxlength="40" required>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <label for="is_admin">Is Admin</label>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,45 @@
 | 
			
		||||
<?php include '_header.html.php' ?>
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
Welcome to Address Book
 | 
			
		||||
<h2>Welcome to Address Book</h2>
 | 
			
		||||
 | 
			
		||||
<?php if(!empty($addresses)): ?>
 | 
			
		||||
<form method="POST">
 | 
			
		||||
<table id="address_table">
 | 
			
		||||
    <tr>
 | 
			
		||||
        <th id="first" onclick="sortBy('first')">First</th>
 | 
			
		||||
        <th id="last" onclick="sortBy('last')">Last</th>
 | 
			
		||||
        <th id="street" onclick="sortBy('street')">Street</th>
 | 
			
		||||
        <th id="zip" onclick="sortBy('zip')">Zip</th>
 | 
			
		||||
        <th id="city" onclick="sortBy('city')">City</th>
 | 
			
		||||
        <th id="phone" onclick="sortBy('phone')">Phone</th>
 | 
			
		||||
        <th colspan="2"> </th>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <?php foreach ($addresses as $address): ?>
 | 
			
		||||
    <?php $id = $address->getId(); ?>
 | 
			
		||||
    <tr id="row_<?= $id ?>">
 | 
			
		||||
            <td><input type="text" id="first_<?= $id ?>" value="<?= $address->getFirst(); ?>" maxlength="80" disabled></td>
 | 
			
		||||
            <td><input type="text" id="last_<?= $id ?>" value="<?= $address->getLast(); ?>" maxlength="80" disabled></td>
 | 
			
		||||
            <td><input type="text" id="street_<?= $id ?>" value="<?= $address->getStreet(); ?>" maxlength="80" disabled></td>
 | 
			
		||||
            <td><input type="text" id="zip_<?= $id ?>" value="<?= $address->getZip(); ?>" maxlength="10" disabled></td>
 | 
			
		||||
            <td><input type="text" id="city_<?= $id ?>" value="<?= $address->getCity(); ?>" maxlength="80" disabled></td>
 | 
			
		||||
            <td><input type="text" id="phone_<?= $id ?>" value="<?= $address->getPhone(); ?>" maxlength="30" disabled></td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="button" value="Edit" id="edit_button_<?= $id ?>" onclick="editAddress('<?= $id ?>')">
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="button" value="Delete" onclick="deleteAddress('<?= $id ?>')">
 | 
			
		||||
                <input type="hidden" id="owner_<?= $id ?>" value="<?= $id ?>">
 | 
			
		||||
            </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <?php endforeach; ?>
 | 
			
		||||
</table>
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
<?php $addAddress = $router->path('address_add'); ?>
 | 
			
		||||
<input type="button" value="Add Address" onclick="addAddress('<?= $addAddress ?>')">
 | 
			
		||||
<?php else: ?>
 | 
			
		||||
Your addresses will be listed soon …
 | 
			
		||||
<?php endif; ?>
 | 
			
		||||
 | 
			
		||||
<?php include '_footer.html.php' ?>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
{% include '_header.tpl' %}
 | 
			
		||||
 | 
			
		||||
<h1>Address Book</h1>
 | 
			
		||||
<a href="/">🏠 Home</a>
 | 
			
		||||
<a href="/">⚙ Admin</a>
 | 
			
		||||
<a href="/">🚪 Login</a>
 | 
			
		||||
 | 
			
		||||
{% include '_footer.tpl' %}
 | 
			
		||||
@@ -5,12 +5,6 @@
 | 
			
		||||
<?php else: ?>
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <?php if ($message): ?>
 | 
			
		||||
        <div class="info">
 | 
			
		||||
            <?= $message ?>
 | 
			
		||||
        </div>
 | 
			
		||||
    <?php endif; ?>
 | 
			
		||||
 | 
			
		||||
    <form method="POST">
 | 
			
		||||
        <label for="nick">Username</label>
 | 
			
		||||
        <input type="text" name="nick" id="nick">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
<?php include dirname(path: __DIR__) . '/_header.html.php'; ?>
 | 
			
		||||
 | 
			
		||||
<h2>404 Page not found</h2>
 | 
			
		||||
 | 
			
		||||
<?php include dirname(path: __DIR__) . '/_footer.html.php' ?>
 | 
			
		||||
The requested URL cannot be found on this server.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user