├── .github └── workflows │ └── phpunit.yml ├── .gitignore ├── README.md ├── app ├── .htaccess ├── Common.php ├── Config │ ├── App.php │ ├── Autoload.php │ ├── Boot │ │ ├── development.php │ │ ├── production.php │ │ └── testing.php │ ├── Cache.php │ ├── Constants.php │ ├── ContentSecurityPolicy.php │ ├── Database.php │ ├── DocTypes.php │ ├── Email.php │ ├── Encryption.php │ ├── Events.php │ ├── Exceptions.php │ ├── Filters.php │ ├── ForeignCharacters.php │ ├── Format.php │ ├── Honeypot.php │ ├── Images.php │ ├── Kint.php │ ├── Logger.php │ ├── Migrations.php │ ├── Mimes.php │ ├── Modules.php │ ├── Pager.php │ ├── Paths.php │ ├── Routes.php │ ├── Services.php │ ├── Toolbar.php │ ├── UserAgents.php │ ├── Validation.php │ └── View.php ├── Controllers │ ├── Ajax.php │ ├── BaseController.php │ ├── Builder.php │ ├── Dashboard.php │ ├── Export.php │ ├── Home.php │ └── Objects.php ├── Database │ ├── Migrations │ │ └── .gitkeep │ └── Seeds │ │ └── .gitkeep ├── Filters │ └── .gitkeep ├── Helpers │ └── .gitkeep ├── Language │ ├── .gitkeep │ └── en │ │ └── Validation.php ├── Libraries │ └── .gitkeep ├── Models │ ├── .gitkeep │ ├── AjaxModel.php │ ├── BuilderModel.php │ └── ObjectModel.php ├── ThirdParty │ └── .gitkeep ├── Views │ ├── ajax │ │ ├── index.php │ │ ├── view_data.php │ │ ├── view_modal.php │ │ └── view_modal_edit.php │ ├── builder │ │ └── index.php │ ├── dashboard │ │ └── index.php │ ├── errors │ │ ├── cli │ │ │ ├── error_404.php │ │ │ ├── error_exception.php │ │ │ └── production.php │ │ └── html │ │ │ ├── debug.css │ │ │ ├── debug.js │ │ │ ├── error_404.php │ │ │ ├── error_exception.php │ │ │ └── production.php │ ├── export │ │ └── pdf.php │ ├── layout │ │ ├── sidebar.php │ │ └── templates.php │ ├── objects │ │ ├── form_add.php │ │ ├── form_update.php │ │ └── index.php │ └── welcome_message.php └── index.html ├── builds ├── composer.json ├── composer.lock ├── db └── starter.sql ├── env ├── license.txt ├── phpunit.xml.dist ├── public ├── .htaccess ├── assets │ ├── demo │ │ ├── chart-area-demo.js │ │ ├── chart-bar-demo.js │ │ ├── chart-pie-demo.js │ │ └── datatables-demo.js │ └── img │ │ └── error-404-monochrome.svg ├── css │ └── styles.css ├── favicon.ico ├── index.php ├── js │ └── scripts.js ├── photos │ ├── 1609652617_aefcf01489903d3b1a03.jpeg │ └── 1609654226_b43f308ecb2f7d206226.jpeg └── robots.txt ├── spark ├── tests ├── README.md ├── _support │ ├── Database │ │ ├── Migrations │ │ │ └── 2020-02-22-222222_example_migration.php │ │ └── Seeds │ │ │ └── ExampleSeeder.php │ ├── DatabaseTestCase.php │ ├── Libraries │ │ └── ConfigReader.php │ ├── Models │ │ └── ExampleModel.php │ └── SessionTestCase.php ├── database │ └── ExampleDatabaseTest.php ├── session │ └── ExampleSessionTest.php └── unit │ └── HealthTest.php └── writable ├── .htaccess ├── cache └── index.html ├── logs └── index.html ├── photo ├── 1609648185_c4e3e1fdbd453680d53d.png ├── 1609648289_1b5b1dbd19d9a09eff4f.png ├── 1609648548_e1a56014f0d182122ed3.png └── 1609648622_442519b223b274aecf6f.png ├── photoindex.html ├── session └── index.html └── uploads └── index.html /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: PHPUnit 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - develop 7 | 8 | jobs: 9 | main: 10 | name: Build and test 11 | 12 | strategy: 13 | matrix: 14 | php-versions: ['7.2', '7.3', '7.4'] 15 | 16 | runs-on: ubuntu-latest 17 | 18 | if: "!contains(github.event.head_commit.message, '[ci skip]')" 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v2 23 | 24 | - name: Setup PHP, with composer and extensions 25 | uses: shivammathur/setup-php@master 26 | with: 27 | php-version: ${{ matrix.php-versions }} 28 | tools: composer, pecl, phpunit 29 | extensions: intl, json, mbstring, mysqlnd, xdebug, xml, sqlite3 30 | coverage: xdebug 31 | 32 | - name: Get composer cache directory 33 | id: composer-cache 34 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 35 | 36 | - name: Cache composer dependencies 37 | uses: actions/cache@v1 38 | with: 39 | path: ${{ steps.composer-cache.outputs.dir }} 40 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} 41 | restore-keys: ${{ runner.os }}-composer- 42 | 43 | - name: Install dependencies 44 | run: composer install --no-progress --no-suggest --no-interaction --prefer-dist --optimize-autoloader 45 | # To prevent rate limiting you may need to supply an OAuth token in Settings > Secrets 46 | # env: 47 | # https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens 48 | # COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} 49 | 50 | - name: Test with phpunit 51 | run: vendor/bin/phpunit --coverage-text 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #------------------------- 2 | # Operating Specific Junk Files 3 | #------------------------- 4 | 5 | # OS X 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # OS X Thumbnails 11 | ._* 12 | 13 | # Windows image file caches 14 | Thumbs.db 15 | ehthumbs.db 16 | Desktop.ini 17 | 18 | # Recycle Bin used on file shares 19 | $RECYCLE.BIN/ 20 | 21 | # Windows Installer files 22 | *.cab 23 | *.msi 24 | *.msm 25 | *.msp 26 | 27 | # Windows shortcuts 28 | *.lnk 29 | 30 | # Linux 31 | *~ 32 | 33 | # KDE directory preferences 34 | .directory 35 | 36 | # Linux trash folder which might appear on any partition or disk 37 | .Trash-* 38 | 39 | #------------------------- 40 | # Environment Files 41 | #------------------------- 42 | # These should never be under version control, 43 | # as it poses a security risk. 44 | .env 45 | .vagrant 46 | Vagrantfile 47 | 48 | #------------------------- 49 | # Temporary Files 50 | #------------------------- 51 | writable/cache/* 52 | !writable/cache/index.html 53 | 54 | writable/logs/* 55 | !writable/logs/index.html 56 | 57 | writable/session/* 58 | !writable/session/index.html 59 | 60 | writable/uploads/* 61 | !writable/uploads/index.html 62 | 63 | writable/debugbar/* 64 | 65 | php_errors.log 66 | 67 | #------------------------- 68 | # User Guide Temp Files 69 | #------------------------- 70 | user_guide_src/build/* 71 | user_guide_src/cilexer/build/* 72 | user_guide_src/cilexer/dist/* 73 | user_guide_src/cilexer/pycilexer.egg-info/* 74 | 75 | #------------------------- 76 | # Test Files 77 | #------------------------- 78 | tests/coverage* 79 | 80 | # Don't save phpunit under version control. 81 | phpunit 82 | 83 | #------------------------- 84 | # Composer 85 | #------------------------- 86 | vendor/ 87 | 88 | #------------------------- 89 | # IDE / Development Files 90 | #------------------------- 91 | 92 | # Modules Testing 93 | _modules/* 94 | 95 | # phpenv local config 96 | .php-version 97 | 98 | # Jetbrains editors (PHPStorm, etc) 99 | .idea/ 100 | *.iml 101 | 102 | # Netbeans 103 | nbproject/ 104 | build/ 105 | nbbuild/ 106 | dist/ 107 | nbdist/ 108 | nbactions.xml 109 | nb-configuration.xml 110 | .nb-gradle/ 111 | 112 | # Sublime Text 113 | *.tmlanguage.cache 114 | *.tmPreferences.cache 115 | *.stTheme.cache 116 | *.sublime-workspace 117 | *.sublime-project 118 | .phpintel 119 | /api/ 120 | 121 | # Visual Studio Code 122 | .vscode/ 123 | 124 | /results/ 125 | /phpunit*.xml 126 | /.phpunit.*.cache 127 | 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeIgniter 4 Application Starter 2 | 3 | ## What is CodeIgniter? 4 | 5 | CodeIgniter is a PHP full-stack web framework that is light, fast, flexible, and secure. 6 | More information can be found at the [official site](http://codeigniter.com). 7 | 8 | This repository holds a composer-installable app starter. 9 | It has been built from the 10 | [development repository](https://github.com/codeigniter4/CodeIgniter4). 11 | 12 | More information about the plans for version 4 can be found in [the announcement](http://forum.codeigniter.com/thread-62615.html) on the forums. 13 | 14 | The user guide corresponding to this version of the framework can be found 15 | [here](https://codeigniter4.github.io/userguide/). 16 | 17 | ## Setup 18 | Copy `env` to `.env` and tailor for your app, specifically the baseURL 19 | and any database settings. 20 | import the database starter.sql to your web database server and run the application with local development server 'php spark serve', Username : user Email : user@gmail.com Password : starter12345 21 | 22 | # Features 23 | CRUD Query Builder with Modal Bootstrap, 24 | CRUD Object Model, 25 | CRUD Ajax jQuery, 26 | Export to PDF with TCPDF, 27 | Export to XLSX with Phpspreadsheet, 28 | Login system with Myth/Auth, 29 | SweetAlert2, 30 | Clean code, 31 | Protection from (SQL injection, CSRF and XSS) 32 | 33 | # Tutorial CodeIgniter 4 34 | Please visit my channel to see exciting CodeIgniter 4 tutorials : [Muba Teknologi Youtube](https://youtube.com/@mubateknologi) 35 | 36 | -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /app/Common.php: -------------------------------------------------------------------------------- 1 | SYSTEMPATH, 37 | * 'App' => APPPATH 38 | * ]; 39 | * 40 | * @var array 41 | */ 42 | public $psr4 = [ 43 | APP_NAMESPACE => APPPATH, // For custom app namespace 44 | 'Config' => APPPATH . 'Config', 45 | ]; 46 | 47 | /** 48 | * ------------------------------------------------------------------- 49 | * Class Map 50 | * ------------------------------------------------------------------- 51 | * The class map provides a map of class names and their exact 52 | * location on the drive. Classes loaded in this manner will have 53 | * slightly faster performance because they will not have to be 54 | * searched for within one or more directories as they would if they 55 | * were being autoloaded through a namespace. 56 | * 57 | * Prototype: 58 | * 59 | * $classmap = [ 60 | * 'MyClass' => '/path/to/class/file.php' 61 | * ]; 62 | * 63 | * @var array 64 | */ 65 | public $classmap = [ 66 | // 'TCPDF' => APPPATH .'vendor/autoload.php', //library mPDF 67 | ]; 68 | } 69 | -------------------------------------------------------------------------------- /app/Config/Boot/development.php: -------------------------------------------------------------------------------- 1 | '127.0.0.1', 82 | 'port' => 11211, 83 | 'weight' => 1, 84 | 'raw' => false, 85 | ]; 86 | 87 | /* 88 | | ------------------------------------------------------------------------- 89 | | Redis settings 90 | | ------------------------------------------------------------------------- 91 | | Your Redis server can be specified below, if you are using 92 | | the Redis or Predis drivers. 93 | | 94 | */ 95 | public $redis = [ 96 | 'host' => '127.0.0.1', 97 | 'password' => null, 98 | 'port' => 6379, 99 | 'timeout' => 0, 100 | 'database' => 0, 101 | ]; 102 | 103 | /* 104 | |-------------------------------------------------------------------------- 105 | | Available Cache Handlers 106 | |-------------------------------------------------------------------------- 107 | | 108 | | This is an array of cache engine alias' and class names. Only engines 109 | | that are listed here are allowed to be used. 110 | | 111 | */ 112 | public $validHandlers = [ 113 | 'dummy' => \CodeIgniter\Cache\Handlers\DummyHandler::class, 114 | 'file' => \CodeIgniter\Cache\Handlers\FileHandler::class, 115 | 'memcached' => \CodeIgniter\Cache\Handlers\MemcachedHandler::class, 116 | 'predis' => \CodeIgniter\Cache\Handlers\PredisHandler::class, 117 | 'redis' => \CodeIgniter\Cache\Handlers\RedisHandler::class, 118 | 'wincache' => \CodeIgniter\Cache\Handlers\WincacheHandler::class, 119 | ]; 120 | } 121 | -------------------------------------------------------------------------------- /app/Config/Constants.php: -------------------------------------------------------------------------------- 1 | '', 34 | 'hostname' => 'localhost', 35 | 'username' => '', 36 | 'password' => '', 37 | 'database' => '', 38 | 'DBDriver' => 'MySQLi', 39 | 'DBPrefix' => '', 40 | 'pConnect' => false, 41 | 'DBDebug' => (ENVIRONMENT !== 'production'), 42 | 'cacheOn' => false, 43 | 'cacheDir' => '', 44 | 'charset' => 'utf8', 45 | 'DBCollat' => 'utf8_general_ci', 46 | 'swapPre' => '', 47 | 'encrypt' => false, 48 | 'compress' => false, 49 | 'strictOn' => false, 50 | 'failover' => [], 51 | 'port' => 3306, 52 | ]; 53 | 54 | /** 55 | * This database connection is used when 56 | * running PHPUnit database tests. 57 | * 58 | * @var array 59 | */ 60 | public $tests = [ 61 | 'DSN' => '', 62 | 'hostname' => '127.0.0.1', 63 | 'username' => '', 64 | 'password' => '', 65 | 'database' => ':memory:', 66 | 'DBDriver' => 'SQLite3', 67 | 'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS 68 | 'pConnect' => false, 69 | 'DBDebug' => (ENVIRONMENT !== 'production'), 70 | 'cacheOn' => false, 71 | 'cacheDir' => '', 72 | 'charset' => 'utf8', 73 | 'DBCollat' => 'utf8_general_ci', 74 | 'swapPre' => '', 75 | 'encrypt' => false, 76 | 'compress' => false, 77 | 'strictOn' => false, 78 | 'failover' => [], 79 | 'port' => 3306, 80 | ]; 81 | 82 | //-------------------------------------------------------------------- 83 | 84 | public function __construct() 85 | { 86 | parent::__construct(); 87 | 88 | // Ensure that we always set the database group to 'tests' if 89 | // we are currently running an automated test suite, so that 90 | // we don't overwrite live data on accident. 91 | if (ENVIRONMENT === 'testing') 92 | { 93 | $this->defaultGroup = 'tests'; 94 | 95 | // Under Travis-CI, we can set an ENV var named 'DB_GROUP' 96 | // so that we can test against multiple databases. 97 | if ($group = getenv('DB')) 98 | { 99 | if (is_file(TESTPATH . 'travis/Database.php')) 100 | { 101 | require TESTPATH . 'travis/Database.php'; 102 | 103 | if (! empty($dbconfig) && array_key_exists($group, $dbconfig)) 104 | { 105 | $this->tests = $dbconfig[$group]; 106 | } 107 | } 108 | } 109 | } 110 | } 111 | 112 | //-------------------------------------------------------------------- 113 | 114 | } 115 | -------------------------------------------------------------------------------- /app/Config/DocTypes.php: -------------------------------------------------------------------------------- 1 | '', 14 | 'xhtml1-strict' => '', 15 | 'xhtml1-trans' => '', 16 | 'xhtml1-frame' => '', 17 | 'xhtml-basic11' => '', 18 | 'html5' => '', 19 | 'html4-strict' => '', 20 | 'html4-trans' => '', 21 | 'html4-frame' => '', 22 | 'mathml1' => '', 23 | 'mathml2' => '', 24 | 'svg10' => '', 25 | 'svg11' => '', 26 | 'svg11-basic' => '', 27 | 'svg11-tiny' => '', 28 | 'xhtml-math-svg-xh' => '', 29 | 'xhtml-math-svg-sh' => '', 30 | 'xhtml-rdfa-1' => '', 31 | 'xhtml-rdfa-2' => '', 32 | ]; 33 | } 34 | -------------------------------------------------------------------------------- /app/Config/Email.php: -------------------------------------------------------------------------------- 1 | 0) 32 | { 33 | ob_end_flush(); 34 | } 35 | 36 | ob_start(function ($buffer) { 37 | return $buffer; 38 | }); 39 | } 40 | 41 | /* 42 | * -------------------------------------------------------------------- 43 | * Debug Toolbar Listeners. 44 | * -------------------------------------------------------------------- 45 | * If you delete, they will no longer be collected. 46 | */ 47 | if (ENVIRONMENT !== 'production') 48 | { 49 | Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'); 50 | Services::toolbar()->respond(); 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /app/Config/Exceptions.php: -------------------------------------------------------------------------------- 1 | \CodeIgniter\Filters\CSRF::class, 11 | 'toolbar' => \CodeIgniter\Filters\DebugToolbar::class, 12 | 'honeypot' => \CodeIgniter\Filters\Honeypot::class, 13 | 'login' => \Myth\Auth\Filters\LoginFilter::class, 14 | 'role' => \Myth\Auth\Filters\RoleFilter::class, 15 | 'permission' => \Myth\Auth\Filters\PermissionFilter::class, 16 | 17 | ]; 18 | 19 | // Always applied before every request 20 | public $globals = [ 21 | 'before' => [ 22 | 'honeypot', 23 | 'login', 24 | // 'csrf' 25 | ], 26 | 'after' => [ 27 | 'toolbar', 28 | //'honeypot' 29 | ], 30 | ]; 31 | 32 | // Works on all of a particular HTTP method 33 | // (GET, POST, etc) as BEFORE filters only 34 | // like: 'post' => ['CSRF', 'throttle'], 35 | public $methods = []; 36 | 37 | // List filter aliases and any before/after uri patterns 38 | // that they should run on, like: 39 | // 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']], 40 | public $filters = []; 41 | } 42 | -------------------------------------------------------------------------------- /app/Config/ForeignCharacters.php: -------------------------------------------------------------------------------- 1 | \CodeIgniter\Format\JSONFormatter::class, 39 | 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, 40 | 'text/xml' => \CodeIgniter\Format\XMLFormatter::class, 41 | ]; 42 | 43 | /* 44 | |-------------------------------------------------------------------------- 45 | | Formatters Options 46 | |-------------------------------------------------------------------------- 47 | | 48 | | Additional Options to adjust default formatters behaviour. 49 | | For each mime type, list the additional options that should be used. 50 | | 51 | */ 52 | public $formatterOptions = [ 53 | 'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES, 54 | 'application/xml' => 0, 55 | 'text/xml' => 0, 56 | ]; 57 | //-------------------------------------------------------------------- 58 | 59 | /** 60 | * A Factory method to return the appropriate formatter for the given mime type. 61 | * 62 | * @param string $mime 63 | * 64 | * @return \CodeIgniter\Format\FormatterInterface 65 | */ 66 | public function getFormatter(string $mime) 67 | { 68 | if (! array_key_exists($mime, $this->formatters)) 69 | { 70 | throw new \InvalidArgumentException('No Formatter defined for mime type: ' . $mime); 71 | } 72 | 73 | $class = $this->formatters[$mime]; 74 | 75 | if (! class_exists($class)) 76 | { 77 | throw new \BadMethodCallException($class . ' is not a valid Formatter.'); 78 | } 79 | 80 | return new $class(); 81 | } 82 | 83 | //-------------------------------------------------------------------- 84 | 85 | } 86 | -------------------------------------------------------------------------------- /app/Config/Honeypot.php: -------------------------------------------------------------------------------- 1 | {label}'; 35 | 36 | /** 37 | * Honeypot container 38 | * 39 | * @var string 40 | */ 41 | public $container = '
{template}
'; 42 | } 43 | -------------------------------------------------------------------------------- /app/Config/Images.php: -------------------------------------------------------------------------------- 1 | \CodeIgniter\Images\Handlers\GDHandler::class, 29 | 'imagick' => \CodeIgniter\Images\Handlers\ImageMagickHandler::class, 30 | ]; 31 | } 32 | -------------------------------------------------------------------------------- /app/Config/Kint.php: -------------------------------------------------------------------------------- 1 | [ 79 | 80 | /* 81 | * The log levels that this handler will handle. 82 | */ 83 | 'handles' => [ 84 | 'critical', 85 | 'alert', 86 | 'emergency', 87 | 'debug', 88 | 'error', 89 | 'info', 90 | 'notice', 91 | 'warning', 92 | ], 93 | 94 | /* 95 | * The default filename extension for log files. 96 | * An extension of 'php' allows for protecting the log files via basic 97 | * scripting, when they are to be stored under a publicly accessible directory. 98 | * 99 | * Note: Leaving it blank will default to 'log'. 100 | */ 101 | 'fileExtension' => '', 102 | 103 | /* 104 | * The file system permissions to be applied on newly created log files. 105 | * 106 | * IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal 107 | * integer notation (i.e. 0700, 0644, etc.) 108 | */ 109 | 'filePermissions' => 0644, 110 | 111 | /* 112 | * Logging Directory Path 113 | * 114 | * By default, logs are written to WRITEPATH . 'logs/' 115 | * Specify a different destination here, if desired. 116 | */ 117 | 'path' => '', 118 | ], 119 | 120 | /** 121 | * The ChromeLoggerHandler requires the use of the Chrome web browser 122 | * and the ChromeLogger extension. Uncomment this block to use it. 123 | */ 124 | // 'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [ 125 | // /* 126 | // * The log levels that this handler will handle. 127 | // */ 128 | // 'handles' => ['critical', 'alert', 'emergency', 'debug', 129 | // 'error', 'info', 'notice', 'warning'], 130 | // ] 131 | ]; 132 | } 133 | -------------------------------------------------------------------------------- /app/Config/Migrations.php: -------------------------------------------------------------------------------- 1 | php spark migrate:create 41 | | 42 | | Typical formats: 43 | | YmdHis_ 44 | | Y-m-d-His_ 45 | | Y_m_d_His_ 46 | | 47 | */ 48 | public $timestampFormat = 'Y-m-d-His_'; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/Config/Modules.php: -------------------------------------------------------------------------------- 1 | 'CodeIgniter\Pager\Views\default_full', 22 | 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 23 | 'default_head' => 'CodeIgniter\Pager\Views\default_head', 24 | ]; 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Items Per Page 29 | |-------------------------------------------------------------------------- 30 | | 31 | | The default number of results shown in a single page. 32 | | 33 | */ 34 | public $perPage = 20; 35 | } 36 | -------------------------------------------------------------------------------- /app/Config/Paths.php: -------------------------------------------------------------------------------- 1 | setDefaultNamespace('App\Controllers'); 20 | $routes->setDefaultController('Home'); 21 | $routes->setDefaultMethod('index'); 22 | $routes->setTranslateURIDashes(false); 23 | $routes->set404Override(); 24 | $routes->setAutoRoute(true); 25 | 26 | /** 27 | * -------------------------------------------------------------------- 28 | * Route Definitions 29 | * -------------------------------------------------------------------- 30 | */ 31 | 32 | // We get a performance increase by specifying the default 33 | // route since we don't have to scan directories. 34 | $routes->get('/', 'Dashboard::index'); 35 | $routes->get('/export-pdf', 'Export::export_pdf'); 36 | $routes->get('/export-excel', 'Export::export_excel'); 37 | 38 | $routes->get('/ajax-jquery', 'Ajax::index'); 39 | $routes->get('/ajax-jquery/get_data', 'Ajax::get_data'); 40 | $routes->get('/ajax-jquery/get_modal', 'Ajax::get_modal'); 41 | $routes->post('/ajax-jquery/save_data', 'Ajax::save_data'); 42 | $routes->post('/ajax-jquery/get_modal_edit', 'Ajax::get_modal_edit'); 43 | $routes->post('/ajax-jquery/update_data', 'Ajax::update_data'); 44 | $routes->post('/ajax-jquery/delete_data', 'Ajax::delete_data'); 45 | 46 | /** 47 | * -------------------------------------------------------------------- 48 | * Additional Routing 49 | * -------------------------------------------------------------------- 50 | * 51 | * There will often be times that you need additional routing and you 52 | * need it to be able to override any defaults in this file. Environment 53 | * based routes is one such time. require() additional route files here 54 | * to make that happen. 55 | * 56 | * You will have access to the $routes object within that file without 57 | * needing to reload it. 58 | */ 59 | if (file_exists(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) { 60 | require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php'; 61 | } 62 | -------------------------------------------------------------------------------- /app/Config/Services.php: -------------------------------------------------------------------------------- 1 | 'Windows 10', 18 | 'windows nt 6.3' => 'Windows 8.1', 19 | 'windows nt 6.2' => 'Windows 8', 20 | 'windows nt 6.1' => 'Windows 7', 21 | 'windows nt 6.0' => 'Windows Vista', 22 | 'windows nt 5.2' => 'Windows 2003', 23 | 'windows nt 5.1' => 'Windows XP', 24 | 'windows nt 5.0' => 'Windows 2000', 25 | 'windows nt 4.0' => 'Windows NT 4.0', 26 | 'winnt4.0' => 'Windows NT 4.0', 27 | 'winnt 4.0' => 'Windows NT', 28 | 'winnt' => 'Windows NT', 29 | 'windows 98' => 'Windows 98', 30 | 'win98' => 'Windows 98', 31 | 'windows 95' => 'Windows 95', 32 | 'win95' => 'Windows 95', 33 | 'windows phone' => 'Windows Phone', 34 | 'windows' => 'Unknown Windows OS', 35 | 'android' => 'Android', 36 | 'blackberry' => 'BlackBerry', 37 | 'iphone' => 'iOS', 38 | 'ipad' => 'iOS', 39 | 'ipod' => 'iOS', 40 | 'os x' => 'Mac OS X', 41 | 'ppc mac' => 'Power PC Mac', 42 | 'freebsd' => 'FreeBSD', 43 | 'ppc' => 'Macintosh', 44 | 'linux' => 'Linux', 45 | 'debian' => 'Debian', 46 | 'sunos' => 'Sun Solaris', 47 | 'beos' => 'BeOS', 48 | 'apachebench' => 'ApacheBench', 49 | 'aix' => 'AIX', 50 | 'irix' => 'Irix', 51 | 'osf' => 'DEC OSF', 52 | 'hp-ux' => 'HP-UX', 53 | 'netbsd' => 'NetBSD', 54 | 'bsdi' => 'BSDi', 55 | 'openbsd' => 'OpenBSD', 56 | 'gnu' => 'GNU/Linux', 57 | 'unix' => 'Unknown Unix OS', 58 | 'symbian' => 'Symbian OS', 59 | ]; 60 | 61 | // The order of this array should NOT be changed. Many browsers return 62 | // multiple browser types so we want to identify the sub-type first. 63 | public $browsers = [ 64 | 'OPR' => 'Opera', 65 | 'Flock' => 'Flock', 66 | 'Edge' => 'Spartan', 67 | 'Chrome' => 'Chrome', 68 | // Opera 10+ always reports Opera/9.80 and appends Version/ to the user agent string 69 | 'Opera.*?Version' => 'Opera', 70 | 'Opera' => 'Opera', 71 | 'MSIE' => 'Internet Explorer', 72 | 'Internet Explorer' => 'Internet Explorer', 73 | 'Trident.* rv' => 'Internet Explorer', 74 | 'Shiira' => 'Shiira', 75 | 'Firefox' => 'Firefox', 76 | 'Chimera' => 'Chimera', 77 | 'Phoenix' => 'Phoenix', 78 | 'Firebird' => 'Firebird', 79 | 'Camino' => 'Camino', 80 | 'Netscape' => 'Netscape', 81 | 'OmniWeb' => 'OmniWeb', 82 | 'Safari' => 'Safari', 83 | 'Mozilla' => 'Mozilla', 84 | 'Konqueror' => 'Konqueror', 85 | 'icab' => 'iCab', 86 | 'Lynx' => 'Lynx', 87 | 'Links' => 'Links', 88 | 'hotjava' => 'HotJava', 89 | 'amaya' => 'Amaya', 90 | 'IBrowse' => 'IBrowse', 91 | 'Maxthon' => 'Maxthon', 92 | 'Ubuntu' => 'Ubuntu Web Browser', 93 | 'Vivaldi' => 'Vivaldi', 94 | ]; 95 | 96 | public $mobiles = [ 97 | // legacy array, old values commented out 98 | 'mobileexplorer' => 'Mobile Explorer', 99 | // 'openwave' => 'Open Wave', 100 | // 'opera mini' => 'Opera Mini', 101 | // 'operamini' => 'Opera Mini', 102 | // 'elaine' => 'Palm', 103 | 'palmsource' => 'Palm', 104 | // 'digital paths' => 'Palm', 105 | // 'avantgo' => 'Avantgo', 106 | // 'xiino' => 'Xiino', 107 | 'palmscape' => 'Palmscape', 108 | // 'nokia' => 'Nokia', 109 | // 'ericsson' => 'Ericsson', 110 | // 'blackberry' => 'BlackBerry', 111 | // 'motorola' => 'Motorola' 112 | 113 | // Phones and Manufacturers 114 | 'motorola' => 'Motorola', 115 | 'nokia' => 'Nokia', 116 | 'palm' => 'Palm', 117 | 'iphone' => 'Apple iPhone', 118 | 'ipad' => 'iPad', 119 | 'ipod' => 'Apple iPod Touch', 120 | 'sony' => 'Sony Ericsson', 121 | 'ericsson' => 'Sony Ericsson', 122 | 'blackberry' => 'BlackBerry', 123 | 'cocoon' => 'O2 Cocoon', 124 | 'blazer' => 'Treo', 125 | 'lg' => 'LG', 126 | 'amoi' => 'Amoi', 127 | 'xda' => 'XDA', 128 | 'mda' => 'MDA', 129 | 'vario' => 'Vario', 130 | 'htc' => 'HTC', 131 | 'samsung' => 'Samsung', 132 | 'sharp' => 'Sharp', 133 | 'sie-' => 'Siemens', 134 | 'alcatel' => 'Alcatel', 135 | 'benq' => 'BenQ', 136 | 'ipaq' => 'HP iPaq', 137 | 'mot-' => 'Motorola', 138 | 'playstation portable' => 'PlayStation Portable', 139 | 'playstation 3' => 'PlayStation 3', 140 | 'playstation vita' => 'PlayStation Vita', 141 | 'hiptop' => 'Danger Hiptop', 142 | 'nec-' => 'NEC', 143 | 'panasonic' => 'Panasonic', 144 | 'philips' => 'Philips', 145 | 'sagem' => 'Sagem', 146 | 'sanyo' => 'Sanyo', 147 | 'spv' => 'SPV', 148 | 'zte' => 'ZTE', 149 | 'sendo' => 'Sendo', 150 | 'nintendo dsi' => 'Nintendo DSi', 151 | 'nintendo ds' => 'Nintendo DS', 152 | 'nintendo 3ds' => 'Nintendo 3DS', 153 | 'wii' => 'Nintendo Wii', 154 | 'open web' => 'Open Web', 155 | 'openweb' => 'OpenWeb', 156 | 157 | // Operating Systems 158 | 'android' => 'Android', 159 | 'symbian' => 'Symbian', 160 | 'SymbianOS' => 'SymbianOS', 161 | 'elaine' => 'Palm', 162 | 'series60' => 'Symbian S60', 163 | 'windows ce' => 'Windows CE', 164 | 165 | // Browsers 166 | 'obigo' => 'Obigo', 167 | 'netfront' => 'Netfront Browser', 168 | 'openwave' => 'Openwave Browser', 169 | 'mobilexplorer' => 'Mobile Explorer', 170 | 'operamini' => 'Opera Mini', 171 | 'opera mini' => 'Opera Mini', 172 | 'opera mobi' => 'Opera Mobile', 173 | 'fennec' => 'Firefox Mobile', 174 | 175 | // Other 176 | 'digital paths' => 'Digital Paths', 177 | 'avantgo' => 'AvantGo', 178 | 'xiino' => 'Xiino', 179 | 'novarra' => 'Novarra Transcoder', 180 | 'vodafone' => 'Vodafone', 181 | 'docomo' => 'NTT DoCoMo', 182 | 'o2' => 'O2', 183 | 184 | // Fallback 185 | 'mobile' => 'Generic Mobile', 186 | 'wireless' => 'Generic Mobile', 187 | 'j2me' => 'Generic Mobile', 188 | 'midp' => 'Generic Mobile', 189 | 'cldc' => 'Generic Mobile', 190 | 'up.link' => 'Generic Mobile', 191 | 'up.browser' => 'Generic Mobile', 192 | 'smartphone' => 'Generic Mobile', 193 | 'cellphone' => 'Generic Mobile', 194 | ]; 195 | 196 | // There are hundreds of bots but these are the most common. 197 | public $robots = [ 198 | 'googlebot' => 'Googlebot', 199 | 'msnbot' => 'MSNBot', 200 | 'baiduspider' => 'Baiduspider', 201 | 'bingbot' => 'Bing', 202 | 'slurp' => 'Inktomi Slurp', 203 | 'yahoo' => 'Yahoo', 204 | 'ask jeeves' => 'Ask Jeeves', 205 | 'fastcrawler' => 'FastCrawler', 206 | 'infoseek' => 'InfoSeek Robot 1.0', 207 | 'lycos' => 'Lycos', 208 | 'yandex' => 'YandexBot', 209 | 'mediapartners-google' => 'MediaPartners Google', 210 | 'CRAZYWEBCRAWLER' => 'Crazy Webcrawler', 211 | 'adsbot-google' => 'AdsBot Google', 212 | 'feedfetcher-google' => 'Feedfetcher Google', 213 | 'curious george' => 'Curious George', 214 | 'ia_archiver' => 'Alexa Crawler', 215 | 'MJ12bot' => 'Majestic-12', 216 | 'Uptimebot' => 'Uptimebot', 217 | ]; 218 | } 219 | -------------------------------------------------------------------------------- /app/Config/Validation.php: -------------------------------------------------------------------------------- 1 | 'CodeIgniter\Validation\Views\list', 31 | 'single' => 'CodeIgniter\Validation\Views\single', 32 | ]; 33 | 34 | //-------------------------------------------------------------------- 35 | // Rules 36 | //-------------------------------------------------------------------- 37 | } 38 | -------------------------------------------------------------------------------- /app/Config/View.php: -------------------------------------------------------------------------------- 1 | ajax = new AjaxModel(); 15 | } 16 | 17 | public function index() 18 | { 19 | $data = [ 20 | 'title' => 'CRUD Ajax jQuery' 21 | ]; 22 | 23 | return view('ajax/index', $data); 24 | } 25 | 26 | public function get_data() 27 | { 28 | if ($this->request->isAJAX()) { 29 | $data = [ 30 | 'data_products' => $this->ajax->findAll() 31 | ]; 32 | 33 | $result = [ 34 | 'output' => view('ajax/view_data', $data) 35 | ]; 36 | 37 | echo json_encode($result); 38 | } else { 39 | exit('404 Not Found'); 40 | } 41 | } 42 | 43 | public function get_modal() 44 | { 45 | if ($this->request->isAJAX()) { 46 | $result = [ 47 | 'output' => view('ajax/view_modal') 48 | ]; 49 | 50 | echo json_encode($result); 51 | } else { 52 | exit('404 Not Found'); 53 | } 54 | } 55 | 56 | public function save_data() 57 | { 58 | if ($this->request->isAJAX()) { 59 | $validation = \Config\Services::validation(); 60 | 61 | $rules = $this->validate([ 62 | 'name' => [ 63 | 'label' => 'product name', 64 | 'rules' => 'required|min_length[3]', 65 | ], 66 | 'description' => [ 67 | 'label' => 'product desc', 68 | 'rules' => 'required|min_length[3]', 69 | ], 70 | 'price' => [ 71 | 'label' => 'product price', 72 | 'rules' => 'required|numeric', 73 | ], 74 | 'date' => [ 75 | 'label' => 'product date', 76 | 'rules' => 'required', 77 | ] 78 | ]); 79 | 80 | if (!$rules) { 81 | $result = [ 82 | 'error' => [ 83 | 'name' => $validation->getError('name'), 84 | 'description' => $validation->getError('description'), 85 | 'price' => $validation->getError('price'), 86 | 'date' => $validation->getError('date') 87 | ] 88 | ]; 89 | } else { 90 | $this->ajax->insert([ 91 | 'name' => strip_tags($this->request->getPost('name')), 92 | 'description' => strip_tags($this->request->getPost('description')), 93 | 'price' => strip_tags($this->request->getPost('price')), 94 | 'date' => strip_tags($this->request->getPost('date')) 95 | ]); 96 | 97 | $result = [ 98 | 'success' => 'Data has been added to database' 99 | ]; 100 | } 101 | echo json_encode($result); 102 | } else { 103 | exit('404 Not Found'); 104 | } 105 | } 106 | 107 | public function get_modal_edit() 108 | { 109 | if ($this->request->isAJAX()) { 110 | $id = $this->request->getVar('id'); 111 | 112 | $row = $this->ajax->find($id); 113 | 114 | $data = [ 115 | 'id' => $row['id'], 116 | 'name' => $row['name'], 117 | 'description' => $row['description'], 118 | 'price' => $row['price'], 119 | 'date' => $row['date'] 120 | ]; 121 | 122 | $result = [ 123 | 'output' => view('ajax/view_modal_edit', $data) 124 | ]; 125 | 126 | echo json_encode($result); 127 | } else { 128 | exit('404 Not Found'); 129 | } 130 | } 131 | 132 | public function update_data() 133 | { 134 | if ($this->request->isAJAX()) { 135 | $validation = \Config\Services::validation(); 136 | 137 | $rules = $this->validate([ 138 | 'name' => [ 139 | 'label' => 'product name', 140 | 'rules' => 'required|min_length[3]', 141 | ], 142 | 'description' => [ 143 | 'label' => 'product desc', 144 | 'rules' => 'required|min_length[3]', 145 | ], 146 | 'price' => [ 147 | 'label' => 'product price', 148 | 'rules' => 'required|numeric', 149 | ], 150 | 'date' => [ 151 | 'label' => 'product date', 152 | 'rules' => 'required', 153 | ] 154 | ]); 155 | 156 | if (!$rules) { 157 | $result = [ 158 | 'error' => [ 159 | 'name' => $validation->getError('name'), 160 | 'description' => $validation->getError('description'), 161 | 'price' => $validation->getError('price'), 162 | 'date' => $validation->getError('date') 163 | ] 164 | ]; 165 | } else { 166 | $id = $this->request->getPost('id'); 167 | $this->ajax->update($id, [ 168 | 'name' => strip_tags($this->request->getPost('name')), 169 | 'description' => strip_tags($this->request->getPost('description')), 170 | 'price' => strip_tags($this->request->getPost('price')), 171 | 'date' => strip_tags($this->request->getPost('date')) 172 | ]); 173 | 174 | $result = [ 175 | 'success' => 'Data has been updated from database' 176 | ]; 177 | } 178 | echo json_encode($result); 179 | } else { 180 | exit('404 Not Found'); 181 | } 182 | } 183 | 184 | public function delete_data() 185 | { 186 | if ($this->request->isAJAX()) { 187 | $id = $this->request->getVar('id'); 188 | 189 | $this->ajax->delete($id); 190 | 191 | $result = [ 192 | 'output' => "Data has been deleted from database" 193 | ]; 194 | 195 | echo json_encode($result); 196 | } else { 197 | exit('404 Not Found'); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /app/Controllers/BaseController.php: -------------------------------------------------------------------------------- 1 | session = \Config\Services::session(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/Controllers/Builder.php: -------------------------------------------------------------------------------- 1 | builderModel = new BuilderModel(); 14 | helper('form'); 15 | } 16 | 17 | public function index() 18 | { 19 | $data = [ 20 | 'title' => 'Crud Query Builder', 21 | 'all_data' => $this->builderModel->select_data() // selecting all data 22 | ]; 23 | 24 | return view('builder/index', $data); 25 | } 26 | 27 | public function add_data() 28 | { 29 | // validation 30 | $rules = $this->validate([ 31 | 'name' => 'required', 32 | 'department' => 'required', 33 | 'position' => 'required', 34 | 'age' => 'required|numeric' 35 | ]); 36 | 37 | if (!$rules) { 38 | session()->setFlashData('failed', \Config\Services::validation()->getErrors()); 39 | return redirect()->back(); 40 | } 41 | 42 | $data = [ 43 | 'name' => $this->request->getPost('name'), 44 | 'department' => $this->request->getPost('department'), 45 | 'position' => $this->request->getPost('position'), 46 | 'age' => $this->request->getPost('age') 47 | ]; 48 | 49 | $this->builderModel->add_data($data); 50 | session()->setFlashData('success', 'data has been added to database.'); 51 | return redirect()->back(); 52 | } 53 | 54 | public function delete_data($id) 55 | { 56 | $this->builderModel->delete_data($id); 57 | session()->setFlashData('success', 'data has been deleted from database.'); 58 | return redirect()->back(); 59 | } 60 | 61 | public function update_data($id) 62 | { 63 | // validation 64 | $rules = $this->validate([ 65 | 'name' => 'required', 66 | 'department' => 'required', 67 | 'position' => 'required', 68 | 'age' => 'required|numeric' 69 | ]); 70 | 71 | if (!$rules) { 72 | session()->setFlashData('failed', \Config\Services::validation()->getErrors()); 73 | return redirect()->back(); 74 | } 75 | 76 | $data = [ 77 | 'name' => $this->request->getPost('name'), 78 | 'department' => $this->request->getPost('department'), 79 | 'position' => $this->request->getPost('position'), 80 | 'age' => $this->request->getPost('age') 81 | ]; 82 | 83 | $this->builderModel->update_data($id, $data); 84 | session()->setFlashData('success', 'data has been updated from database.'); 85 | return redirect()->back(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/Controllers/Dashboard.php: -------------------------------------------------------------------------------- 1 | 'Starter Project CodeIgniter 4' 11 | ]; 12 | 13 | return view('dashboard/index', $data); 14 | } 15 | } -------------------------------------------------------------------------------- /app/Controllers/Export.php: -------------------------------------------------------------------------------- 1 | db = \Config\Database::connect(); 16 | $this->builder = $this->db->table('peoples'); 17 | } 18 | 19 | public function export_pdf() 20 | { 21 | $data = [ 22 | 'pdf_peoples' => $this->builder->get()->getResultArray() 23 | ]; 24 | 25 | $html = view('export/pdf', $data); 26 | 27 | // create new PDF document 28 | $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); 29 | 30 | 31 | // set margins 32 | $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_RIGHT); 33 | $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); 34 | 35 | // Add a page 36 | // This method has several options, check the source code documentation for more information. 37 | $pdf->AddPage(); 38 | 39 | // Print text using writeHTMLCell() 40 | $pdf->writeHTML($html); 41 | $this->response->setContentType('application/pdf'); 42 | // Close and output PDF document 43 | // This method has several options, check the source code documentation for more information. 44 | $pdf->Output('peoples.pdf', 'I'); 45 | } 46 | 47 | public function export_excel() 48 | { 49 | $peoples = $this->builder->get()->getResultArray(); 50 | 51 | $spreadsheet = new Spreadsheet(); 52 | // tulis header/nama kolom 53 | $spreadsheet->setActiveSheetIndex(0) 54 | ->setCellValue('A1', 'No') 55 | ->setCellValue('B1', 'Name') 56 | ->setCellValue('C1', 'Address') 57 | ->setCellValue('D1', 'Email') 58 | ->setCellValue('E1', 'Birthdate'); 59 | 60 | $column = 2; 61 | // tulis data mobil ke cell 62 | $no = 1; 63 | foreach ($peoples as $data) { 64 | $spreadsheet->setActiveSheetIndex(0) 65 | ->setCellValue('A' . $column, $no++) 66 | ->setCellValue('B' . $column, $data['name']) 67 | ->setCellValue('C' . $column, $data['address']) 68 | ->setCellValue('D' . $column, $data['email']) 69 | ->setCellValue('E' . $column, $data['birthdate']); 70 | $column++; 71 | } 72 | // tulis dalam format .xlsx 73 | $writer = new Xlsx($spreadsheet); 74 | $fileName = 'Peoples Data'; 75 | 76 | // Redirect hasil generate xlsx ke web client 77 | header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); 78 | header('Content-Disposition: attachment;filename=' . $fileName . '.xlsx'); 79 | header('Cache-Control: max-age=0'); 80 | 81 | $writer->save('php://output'); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/Controllers/Home.php: -------------------------------------------------------------------------------- 1 | objectModel = new ObjectModel(); 14 | helper('form'); 15 | } 16 | 17 | public function index() 18 | { 19 | $data = [ 20 | 'title' => 'CRUD Object Model', 21 | 'all_data' => $this->objectModel->findAll() 22 | ]; 23 | 24 | return view('objects/index', $data); 25 | } 26 | 27 | public function add_data() 28 | { 29 | $data['title'] = 'Add Data'; 30 | if ($this->request->getPost()) { 31 | $rules = [ 32 | 'name' => 'required|alpha_space', 33 | 'gender' => 'required', 34 | 'address' => 'required', 35 | 'photo' => 'uploaded[photo]|max_size[photo,2048]|is_image[photo]|mime_in[photo,image/jpg,image/jpeg,image/png]' 36 | ]; 37 | 38 | if ($this->validate($rules)) { 39 | $photo = $this->request->getFile('photo'); 40 | $photoName = $photo->getRandomName(); 41 | $photo->move('photos', $photoName); 42 | 43 | $inserted = [ 44 | 'name' => $this->request->getPost('name'), 45 | 'gender' => $this->request->getPost('gender'), 46 | 'address' => $this->request->getPost('address'), 47 | 'photo' => $photoName 48 | ]; 49 | 50 | $this->objectModel->insert($inserted); 51 | session()->setFlashData('success', 'data has been added to database'); 52 | return redirect()->to('/objects'); 53 | } else { 54 | session()->setFlashData('failed', \Config\Services::validation()->getErrors()); 55 | return redirect()->back()->withInput(); 56 | } 57 | } 58 | return view('objects/form_add', $data); 59 | } 60 | 61 | public function delete_data($id) 62 | { 63 | $photoId = $this->objectModel->find($id); 64 | unlink('photos/'.$photoId['photo']); 65 | 66 | $this->objectModel->delete($id); 67 | session()->setFlashData('success', 'data has been deleted from database.'); 68 | return redirect()->to('/objects'); 69 | } 70 | 71 | public function update_data($id) 72 | { 73 | $data = [ 74 | 'title' => 'Update Data', 75 | 'dataById' => $this->objectModel->where('id', $id)->first() 76 | ]; 77 | 78 | if ($this->request->getPost()) { 79 | $rules = [ 80 | 'name' => 'required|alpha_space', 81 | 'gender' => 'required', 82 | 'address' => 'required', 83 | 'photo' => 'max_size[photo,2048]|is_image[photo]|mime_in[photo,image/jpg,image/jpeg,image/png]' 84 | ]; 85 | 86 | if ($this->validate($rules)) { 87 | $photo = $this->request->getFile('photo'); 88 | if ($photo->getError() == 4) { 89 | $photoName = $this->request->getPost('Oldphoto'); 90 | } else { 91 | $photoName = $photo->getRandomName(); 92 | $photo->move('photos', $photoName); 93 | $photo = $this->objectModel->find($id); 94 | if ($photo['photo'] == $photo['photo']) { 95 | unlink('photos/' . $this->request->getPost('Oldphoto')); 96 | } 97 | } 98 | 99 | $inserted = [ 100 | 'name' => $this->request->getPost('name'), 101 | 'gender' => $this->request->getPost('gender'), 102 | 'address' => $this->request->getPost('address'), 103 | 'photo' => $photoName 104 | ]; 105 | 106 | $this->objectModel->update($id, $inserted); 107 | session()->setFlashData('success', 'data has been updated from database'); 108 | return redirect()->to('/objects'); 109 | } else { 110 | session()->setFlashData('failed', \Config\Services::validation()->getErrors()); 111 | return redirect()->back()->withInput(); 112 | } 113 | } 114 | return view('objects/form_update', $data); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/Database/Migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/app/Database/Migrations/.gitkeep -------------------------------------------------------------------------------- /app/Database/Seeds/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/app/Database/Seeds/.gitkeep -------------------------------------------------------------------------------- /app/Filters/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/app/Filters/.gitkeep -------------------------------------------------------------------------------- /app/Helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/app/Helpers/.gitkeep -------------------------------------------------------------------------------- /app/Language/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/app/Language/.gitkeep -------------------------------------------------------------------------------- /app/Language/en/Validation.php: -------------------------------------------------------------------------------- 1 | db = \Config\Database::connect(); 14 | $this->builder = $this->db->table('employees'); // tabel employees 15 | } 16 | 17 | // func select all data or by id 18 | public function select_data($id = FALSE) 19 | { 20 | if ($id == FALSE) { 21 | return $this->builder->get()->getResultObject(); 22 | } 23 | 24 | return $this->builder->getWhere(['id' => $id])->getRow(); 25 | } 26 | 27 | // func insert data to db 28 | public function add_data($data) 29 | { 30 | $this->builder->insert($data); 31 | } 32 | 33 | // func delete data from db 34 | public function delete_data($id) 35 | { 36 | $this->builder->where('id', $id); 37 | $this->builder->delete(); 38 | } 39 | 40 | // func update data from db 41 | public function update_data($id, $data) 42 | { 43 | $this->builder->where('id', $id); 44 | $this->builder->update($data); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Models/ObjectModel.php: -------------------------------------------------------------------------------- 1 | extend('layout/templates'); ?> 2 | 3 | Section('content'); ?> 4 |
5 |
6 |
7 |

CRUD Ajax jQuery

8 | 12 |
13 |
14 | 15 | Products Table 16 |
17 |
18 | Add data 19 | 20 | 21 |
22 | 23 |
24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 68 | 69 | endSection(); ?> -------------------------------------------------------------------------------- /app/Views/ajax/view_data.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 31 | 32 | 33 | 34 |
NoNameDescriptionPriceDateOption
23 | 26 | 27 | 30 |
35 |
36 | 37 | -------------------------------------------------------------------------------- /app/Views/ajax/view_modal.php: -------------------------------------------------------------------------------- 1 | 2 | 62 | 63 | -------------------------------------------------------------------------------- /app/Views/ajax/view_modal_edit.php: -------------------------------------------------------------------------------- 1 | 2 | 63 | 64 | -------------------------------------------------------------------------------- /app/Views/dashboard/index.php: -------------------------------------------------------------------------------- 1 | extend('layout/templates'); ?> 2 | 3 | Section('content'); ?> 4 | 5 |
6 |
7 |
8 |

Dashboard

9 | 12 |
13 |
14 |
15 |
Primary Card
16 | 20 |
21 |
22 |
23 |
24 |
Warning Card
25 | 29 |
30 |
31 |
32 |
33 |
Success Card
34 | 38 |
39 |
40 |
41 |
42 |
Danger Card
43 | 47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 | Area Chart Example 56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 | Bar Chart Example 65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | 73 | endSection(); ?> -------------------------------------------------------------------------------- /app/Views/errors/cli/error_404.php: -------------------------------------------------------------------------------- 1 | 4 | Message: 5 | Filename: getFile(), "\n"; ?> 6 | Line Number: getLine(); ?> 7 | 8 | 9 | 10 | Backtrace: 11 | getTrace() as $error): ?> 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/Views/errors/cli/production.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 Page Not Found 6 | 7 | 70 | 71 | 72 |
73 |

404 - File Not Found

74 | 75 |

76 | 77 | 78 | 79 | Sorry! Cannot seem to find the page you were looking for. 80 | 81 |

82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /app/Views/errors/html/production.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Whoops! 8 | 9 | 12 | 13 | 14 | 15 |
16 | 17 |

Whoops!

18 | 19 |

We seem to have hit a snag. Please try again later...

20 | 21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/Views/export/pdf.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Print PDF 13 | 14 | 15 | 16 | 17 |
18 |

List of Peoples

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
NoNameAddressEmailBirthdate
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/Views/layout/sidebar.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 45 |
-------------------------------------------------------------------------------- /app/Views/layout/templates.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <?= $title; ?> 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 45 | 46 | include('layout/sidebar'); ?> 47 | 48 | 49 | renderSection('content'); ?> 50 | 51 | 52 | 64 |
65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 95 | 96 | 97 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /app/Views/objects/form_add.php: -------------------------------------------------------------------------------- 1 | extend('layout/templates'); ?> 2 | 3 | Section('content'); ?> 4 |
5 |
6 |
7 |

CRUD Object Model

8 | 13 |
14 |
15 | 16 | Form Add 17 |
18 |
19 | getFlashdata('failed'); 21 | if (!empty($errors)) : ?> 22 | 33 | 34 | 35 | 37 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 53 |
54 |
55 | 56 |
57 | 58 | 61 |
62 |
63 | 64 | 67 |
68 |
69 |
70 | 71 | 72 |
73 |
74 | 75 | 76 |
77 | 78 | Back 79 | 80 |
81 |
82 |
83 |
84 | endSection(); ?> -------------------------------------------------------------------------------- /app/Views/objects/form_update.php: -------------------------------------------------------------------------------- 1 | extend('layout/templates'); ?> 2 | 3 | Section('content'); ?> 4 |
5 |
6 |
7 |

CRUD Object Model

8 | 13 |
14 |
15 | 16 | Form Update 17 |
18 |
19 | getFlashdata('failed'); 21 | if (!empty($errors)) : ?> 22 | 33 | 34 | 35 | 37 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 |
56 |
57 | 58 | 59 |
60 | > 61 | 64 |
65 |
66 | 67 | 70 |
71 | 72 |
73 | 74 | 77 |
78 |
79 | > 80 | 83 |
84 | 85 |
86 |
87 | 88 | 89 |
90 |
91 | 92 | 93 |
94 | Previous photo Previous photo 95 | 96 | Back 97 | 98 |
99 |
100 |
101 |
102 | endSection(); ?> -------------------------------------------------------------------------------- /app/Views/objects/index.php: -------------------------------------------------------------------------------- 1 | extend('layout/templates'); ?> 2 | 3 | Section('content'); ?> 4 |
5 |
6 |
7 |

CRUD Object Model

8 | 12 |
13 |
14 | 15 | Students Table 16 |
17 |
18 | Add data 19 | 20 | getFlashdata('failed'); 22 | if (!empty($errors)) : ?> 23 | 34 | 35 | 36 | getFlashData('success')) : ?> 37 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 59 | 60 | 61 | 62 | 63 | 64 | 67 | 75 | 76 | 77 | 78 |
NoNameGenderAddressPhotoOption
65 | photo 66 | 68 | 69 | Update 70 | 71 | 72 | Delete 73 | 74 |
79 |
80 |
81 |
82 |
83 |
84 | 85 | 86 | 87 | 110 | 111 | endSection(); ?> -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /builds: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 'vcs', 68 | 'url' => GITHUB_URL, 69 | ]; 70 | } 71 | 72 | // Define the "require" 73 | $array['require']['codeigniter4/codeigniter4'] = 'dev-develop'; 74 | unset($array['require']['codeigniter4/framework']); 75 | } 76 | 77 | // Release 78 | else 79 | { 80 | // Clear 'minimum-stability' 81 | unset($array['minimum-stability']); 82 | 83 | // If the repo is configured then clear it 84 | if (isset($array['repositories'])) 85 | { 86 | // Check for the CodeIgniter repo 87 | foreach ($array['repositories'] as $i => $repository) 88 | { 89 | if ($repository['url'] == GITHUB_URL) 90 | { 91 | unset($array['repositories'][$i]); 92 | break; 93 | } 94 | } 95 | if (empty($array['repositories'])) 96 | { 97 | unset($array['repositories']); 98 | } 99 | } 100 | 101 | // Define the "require" 102 | $array['require']['codeigniter4/framework'] = LATEST_RELEASE; 103 | unset($array['require']['codeigniter4/codeigniter4']); 104 | } 105 | 106 | // Write out a new composer.json 107 | file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES) . PHP_EOL); 108 | $modified[] = $file; 109 | } 110 | else 111 | { 112 | echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL; 113 | } 114 | } 115 | else 116 | { 117 | echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL; 118 | } 119 | } 120 | 121 | // Paths config and PHPUnit XMLs 122 | $files = [ 123 | __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php', 124 | __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist', 125 | __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml', 126 | ]; 127 | 128 | foreach ($files as $file) 129 | { 130 | if (is_file($file)) 131 | { 132 | $contents = file_get_contents($file); 133 | 134 | // Development 135 | if ($dev) 136 | { 137 | $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents); 138 | } 139 | 140 | // Release 141 | else 142 | { 143 | $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents); 144 | } 145 | 146 | file_put_contents($file, $contents); 147 | $modified[] = $file; 148 | } 149 | } 150 | 151 | if (empty($modified)) 152 | { 153 | echo 'No files modified' . PHP_EOL; 154 | } 155 | else 156 | { 157 | echo 'The following files were modified:' . PHP_EOL; 158 | foreach ($modified as $file) 159 | { 160 | echo " * {$file}" . PHP_EOL; 161 | } 162 | echo 'Run `composer update` to sync changes with your vendor folder' . PHP_EOL; 163 | } 164 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codeigniter4/appstarter", 3 | "type": "project", 4 | "description": "CodeIgniter4 starter app", 5 | "homepage": "https://codeigniter.com", 6 | "license": "MIT", 7 | "minimum-stability": "dev", 8 | "prefer-stable": true, 9 | "require": { 10 | "php": ">=7.2", 11 | "codeigniter4/framework": "^4", 12 | "tecnickcom/tcpdf": "^6.3", 13 | "phpoffice/phpspreadsheet": "^1.16", 14 | "myth/auth": "^1.0@beta" 15 | }, 16 | "require-dev": { 17 | "fzaninotto/faker": "^1.9@dev", 18 | "mikey179/vfsstream": "1.6.*", 19 | "phpunit/phpunit": "^8.5" 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "Tests\\Support\\": "tests/_support" 24 | } 25 | }, 26 | "scripts": { 27 | "post-update-cmd": [ 28 | "@composer dump-autoload" 29 | ], 30 | "test": "phpunit" 31 | }, 32 | "support": { 33 | "forum": "http://forum.codeigniter.com/", 34 | "source": "https://github.com/codeigniter4/CodeIgniter4", 35 | "slack": "https://codeigniterchat.slack.com" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /env: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------- 2 | # Example Environment Configuration file 3 | # 4 | # This file can be used as a starting point for your own 5 | # custom .env files, and contains most of the possible settings 6 | # available in a default install. 7 | # 8 | # By default, all of the settings are commented out. If you want 9 | # to override the setting, you must un-comment it by removing the '#' 10 | # at the beginning of the line. 11 | #-------------------------------------------------------------------- 12 | 13 | #-------------------------------------------------------------------- 14 | # ENVIRONMENT 15 | #-------------------------------------------------------------------- 16 | 17 | # CI_ENVIRONMENT = production 18 | 19 | #-------------------------------------------------------------------- 20 | # APP 21 | #-------------------------------------------------------------------- 22 | 23 | # app.baseURL = '' 24 | # app.forceGlobalSecureRequests = false 25 | 26 | # app.sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler' 27 | # app.sessionCookieName = 'ci_session' 28 | # app.sessionSavePath = NULL 29 | # app.sessionMatchIP = false 30 | # app.sessionTimeToUpdate = 300 31 | # app.sessionRegenerateDestroy = false 32 | 33 | # app.cookiePrefix = '' 34 | # app.cookieDomain = '' 35 | # app.cookiePath = '/' 36 | # app.cookieSecure = false 37 | # app.cookieHTTPOnly = false 38 | 39 | # app.CSRFProtection = false 40 | # app.CSRFTokenName = 'csrf_test_name' 41 | # app.CSRFCookieName = 'csrf_cookie_name' 42 | # app.CSRFExpire = 7200 43 | # app.CSRFRegenerate = true 44 | # app.CSRFExcludeURIs = [] 45 | 46 | # app.CSPEnabled = false 47 | 48 | #-------------------------------------------------------------------- 49 | # DATABASE 50 | #-------------------------------------------------------------------- 51 | 52 | # database.default.hostname = localhost 53 | # database.default.database = ci4 54 | # database.default.username = root 55 | # database.default.password = root 56 | # database.default.DBDriver = MySQLi 57 | 58 | # database.tests.hostname = localhost 59 | # database.tests.database = ci4 60 | # database.tests.username = root 61 | # database.tests.password = root 62 | # database.tests.DBDriver = MySQLi 63 | 64 | #-------------------------------------------------------------------- 65 | # CONTENT SECURITY POLICY 66 | #-------------------------------------------------------------------- 67 | 68 | # contentsecuritypolicy.reportOnly = false 69 | # contentsecuritypolicy.defaultSrc = 'none' 70 | # contentsecuritypolicy.scriptSrc = 'self' 71 | # contentsecuritypolicy.styleSrc = 'self' 72 | # contentsecuritypolicy.imageSrc = 'self' 73 | # contentsecuritypolicy.base_uri = null 74 | # contentsecuritypolicy.childSrc = null 75 | # contentsecuritypolicy.connectSrc = 'self' 76 | # contentsecuritypolicy.fontSrc = null 77 | # contentsecuritypolicy.formAction = null 78 | # contentsecuritypolicy.frameAncestors = null 79 | # contentsecuritypolicy.mediaSrc = null 80 | # contentsecuritypolicy.objectSrc = null 81 | # contentsecuritypolicy.pluginTypes = null 82 | # contentsecuritypolicy.reportURI = null 83 | # contentsecuritypolicy.sandbox = false 84 | # contentsecuritypolicy.upgradeInsecureRequests = false 85 | 86 | #-------------------------------------------------------------------- 87 | # ENCRYPTION 88 | #-------------------------------------------------------------------- 89 | 90 | # encryption.key = 91 | # encryption.driver = OpenSSL 92 | 93 | #-------------------------------------------------------------------- 94 | # HONEYPOT 95 | #-------------------------------------------------------------------- 96 | 97 | # honeypot.hidden = 'true' 98 | # honeypot.label = 'Fill This Field' 99 | # honeypot.name = 'honeypot' 100 | # honeypot.template = '' 101 | # honeypot.container = '
{template}
' 102 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2019 British Columbia Institute of Technology 4 | Copyright (c) 2019-2020 CodeIgniter Foundation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests 15 | 16 | 17 | 18 | 19 | 20 | ./app 21 | 22 | ./app/Views 23 | ./app/Config/Routes.php 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | # Disable directory browsing 2 | Options All -Indexes 3 | 4 | # ---------------------------------------------------------------------- 5 | # Rewrite engine 6 | # ---------------------------------------------------------------------- 7 | 8 | # Turning on the rewrite engine is necessary for the following rules and features. 9 | # FollowSymLinks must be enabled for this to work. 10 | 11 | Options +FollowSymlinks 12 | RewriteEngine On 13 | 14 | # If you installed CodeIgniter in a subfolder, you will need to 15 | # change the following line to match the subfolder you need. 16 | # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase 17 | # RewriteBase / 18 | 19 | # Redirect Trailing Slashes... 20 | RewriteCond %{REQUEST_FILENAME} !-d 21 | RewriteRule ^(.*)/$ /$1 [L,R=301] 22 | 23 | # Rewrite "www.example.com -> example.com" 24 | RewriteCond %{HTTPS} !=on 25 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 26 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 27 | 28 | # Checks to see if the user is attempting to access a valid file, 29 | # such as an image or css document, if this isn't true it sends the 30 | # request to the front controller, index.php 31 | RewriteCond %{REQUEST_FILENAME} !-f 32 | RewriteCond %{REQUEST_FILENAME} !-d 33 | RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA] 34 | 35 | # Ensure Authorization header is passed along 36 | RewriteCond %{HTTP:Authorization} . 37 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 38 | 39 | 40 | 41 | # If we don't have mod_rewrite installed, all 404's 42 | # can be sent to index.php, and everything works as normal. 43 | ErrorDocument 404 index.php 44 | 45 | 46 | # Disable server signature start 47 | ServerSignature Off 48 | # Disable server signature end 49 | -------------------------------------------------------------------------------- /public/assets/demo/chart-area-demo.js: -------------------------------------------------------------------------------- 1 | // Set new default font family and font color to mimic Bootstrap's default styling 2 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 3 | Chart.defaults.global.defaultFontColor = '#292b2c'; 4 | 5 | // Area Chart Example 6 | var ctx = document.getElementById("myAreaChart"); 7 | var myLineChart = new Chart(ctx, { 8 | type: 'line', 9 | data: { 10 | labels: ["Mar 1", "Mar 2", "Mar 3", "Mar 4", "Mar 5", "Mar 6", "Mar 7", "Mar 8", "Mar 9", "Mar 10", "Mar 11", "Mar 12", "Mar 13"], 11 | datasets: [{ 12 | label: "Sessions", 13 | lineTension: 0.3, 14 | backgroundColor: "rgba(2,117,216,0.2)", 15 | borderColor: "rgba(2,117,216,1)", 16 | pointRadius: 5, 17 | pointBackgroundColor: "rgba(2,117,216,1)", 18 | pointBorderColor: "rgba(255,255,255,0.8)", 19 | pointHoverRadius: 5, 20 | pointHoverBackgroundColor: "rgba(2,117,216,1)", 21 | pointHitRadius: 50, 22 | pointBorderWidth: 2, 23 | data: [10000, 30162, 26263, 18394, 18287, 28682, 31274, 33259, 25849, 24159, 32651, 31984, 38451], 24 | }], 25 | }, 26 | options: { 27 | scales: { 28 | xAxes: [{ 29 | time: { 30 | unit: 'date' 31 | }, 32 | gridLines: { 33 | display: false 34 | }, 35 | ticks: { 36 | maxTicksLimit: 7 37 | } 38 | }], 39 | yAxes: [{ 40 | ticks: { 41 | min: 0, 42 | max: 40000, 43 | maxTicksLimit: 5 44 | }, 45 | gridLines: { 46 | color: "rgba(0, 0, 0, .125)", 47 | } 48 | }], 49 | }, 50 | legend: { 51 | display: false 52 | } 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /public/assets/demo/chart-bar-demo.js: -------------------------------------------------------------------------------- 1 | // Set new default font family and font color to mimic Bootstrap's default styling 2 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 3 | Chart.defaults.global.defaultFontColor = '#292b2c'; 4 | 5 | // Bar Chart Example 6 | var ctx = document.getElementById("myBarChart"); 7 | var myLineChart = new Chart(ctx, { 8 | type: 'bar', 9 | data: { 10 | labels: ["January", "February", "March", "April", "May", "June"], 11 | datasets: [{ 12 | label: "Revenue", 13 | backgroundColor: "rgba(2,117,216,1)", 14 | borderColor: "rgba(2,117,216,1)", 15 | data: [4215, 5312, 6251, 7841, 9821, 14984], 16 | }], 17 | }, 18 | options: { 19 | scales: { 20 | xAxes: [{ 21 | time: { 22 | unit: 'month' 23 | }, 24 | gridLines: { 25 | display: false 26 | }, 27 | ticks: { 28 | maxTicksLimit: 6 29 | } 30 | }], 31 | yAxes: [{ 32 | ticks: { 33 | min: 0, 34 | max: 15000, 35 | maxTicksLimit: 5 36 | }, 37 | gridLines: { 38 | display: true 39 | } 40 | }], 41 | }, 42 | legend: { 43 | display: false 44 | } 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /public/assets/demo/chart-pie-demo.js: -------------------------------------------------------------------------------- 1 | // Set new default font family and font color to mimic Bootstrap's default styling 2 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 3 | Chart.defaults.global.defaultFontColor = '#292b2c'; 4 | 5 | // Pie Chart Example 6 | var ctx = document.getElementById("myPieChart"); 7 | var myPieChart = new Chart(ctx, { 8 | type: 'pie', 9 | data: { 10 | labels: ["Blue", "Red", "Yellow", "Green"], 11 | datasets: [{ 12 | data: [12.21, 15.58, 11.25, 8.32], 13 | backgroundColor: ['#007bff', '#dc3545', '#ffc107', '#28a745'], 14 | }], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /public/assets/demo/datatables-demo.js: -------------------------------------------------------------------------------- 1 | // Call the dataTables jQuery plugin 2 | $(document).ready(function() { 3 | $('#dataTable').DataTable(); 4 | }); 5 | -------------------------------------------------------------------------------- /public/assets/img/error-404-monochrome.svg: -------------------------------------------------------------------------------- 1 | error-404-monochrome -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | systemDirectory, '/ ') . '/bootstrap.php'; 37 | 38 | /* 39 | *--------------------------------------------------------------- 40 | * LAUNCH THE APPLICATION 41 | *--------------------------------------------------------------- 42 | * Now that everything is setup, it's time to actually fire 43 | * up the engines and make this app do its thang. 44 | */ 45 | $app->run(); 46 | -------------------------------------------------------------------------------- /public/js/scripts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin v6.0.1 (https://startbootstrap.com/templates/sb-admin) 3 | * Copyright 2013-2020 Start Bootstrap 4 | * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */ 6 | (function($) { 7 | "use strict"; 8 | 9 | // Add active state to sidbar nav links 10 | var path = window.location.href; // because the 'href' property of the DOM element is the absolute path 11 | $("#layoutSidenav_nav .sb-sidenav a.nav-link").each(function() { 12 | if (this.href === path) { 13 | $(this).addClass("active"); 14 | } 15 | }); 16 | 17 | // Toggle the side navigation 18 | $("#sidebarToggle").on("click", function(e) { 19 | e.preventDefault(); 20 | $("body").toggleClass("sb-sidenav-toggled"); 21 | }); 22 | })(jQuery); 23 | -------------------------------------------------------------------------------- /public/photos/1609652617_aefcf01489903d3b1a03.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/public/photos/1609652617_aefcf01489903d3b1a03.jpeg -------------------------------------------------------------------------------- /public/photos/1609654226_b43f308ecb2f7d206226.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/public/photos/1609654226_b43f308ecb2f7d206226.jpeg -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /spark: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | systemDirectory, '/ ') . '/bootstrap.php'; 45 | 46 | // Grab our Console 47 | $console = new \CodeIgniter\CLI\Console($app); 48 | 49 | // We want errors to be shown when using it from the CLI. 50 | error_reporting(-1); 51 | ini_set('display_errors', 1); 52 | 53 | // Show basic information before we do anything else. 54 | $console->showHeader(); 55 | 56 | // fire off the command in the main framework. 57 | $response = $console->run(); 58 | if ($response->getStatusCode() >= 300) 59 | { 60 | exit($response->getStatusCode()); 61 | } 62 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Running Application Tests 2 | 3 | This is the quick-start to CodeIgniter testing. Its intent is to describe what 4 | it takes to set up your application and get it ready to run unit tests. 5 | It is not intended to be a full description of the test features that you can 6 | use to test your application. Those details can be found in the documentation. 7 | 8 | ## Resources 9 | * [CodeIgniter 4 User Guide on Testing](https://codeigniter4.github.io/userguide/testing/index.html) 10 | * [PHPUnit docs](https://phpunit.readthedocs.io/en/8.3/index.html) 11 | 12 | ## Requirements 13 | 14 | It is recommended to use the latest version of PHPUnit. At the time of this 15 | writing we are running version 8.5.2. Support for this has been built into the 16 | **composer.json** file that ships with CodeIgniter and can easily be installed 17 | via [Composer](https://getcomposer.org/) if you don't already have it installed globally. 18 | 19 | > composer install 20 | 21 | If running under OS X or Linux, you can create a symbolic link to make running tests a touch nicer. 22 | 23 | > ln -s ./vendor/bin/phpunit ./phpunit 24 | 25 | You also need to install [XDebug](https://xdebug.org/index.php) in order 26 | for code coverage to be calculated successfully. 27 | 28 | ## Setting Up 29 | 30 | A number of the tests use a running database. 31 | In order to set up the database edit the details for the `tests` group in 32 | **app/Config/Database.php** or **phpunit.xml**. Make sure that you provide a database engine 33 | that is currently running on your machine. More details on a test database setup are in the 34 | *Docs>>Testing>>Testing Your Database* section of the documentation. 35 | 36 | If you want to run the tests without using live database you can 37 | exclude @DatabaseLive group. Or make a copy of **phpunit.dist.xml** - 38 | call it **phpunit.xml** - and comment out the named "database". This will make 39 | the tests run quite a bit faster. 40 | 41 | ## Running the tests 42 | 43 | The entire test suite can be run by simply typing one command-line command from the main directory. 44 | 45 | > ./phpunit 46 | 47 | You can limit tests to those within a single test directory by specifying the 48 | directory name after phpunit. 49 | 50 | > ./phpunit app/Models 51 | 52 | ## Generating Code Coverage 53 | 54 | To generate coverage information, including HTML reports you can view in your browser, 55 | you can use the following command: 56 | 57 | > ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m 58 | 59 | This runs all of the tests again collecting information about how many lines, 60 | functions, and files are tested. It also reports the percentage of the code that is covered by tests. 61 | It is collected in two formats: a simple text file that provides an overview as well 62 | as a comprehensive collection of HTML files that show the status of every line of code in the project. 63 | 64 | The text file can be found at **tests/coverage.txt**. 65 | The HTML files can be viewed by opening **tests/coverage/index.html** in your favorite browser. 66 | 67 | ## PHPUnit XML Configuration 68 | 69 | The repository has a ``phpunit.xml.dist`` file in the project root that's used for 70 | PHPUnit configuration. This is used to provide a default configuration if you 71 | do not have your own configuration file in the project root. 72 | 73 | The normal practice would be to copy ``phpunit.xml.dist`` to ``phpunit.xml`` 74 | (which is git ignored), and to tailor it as you see fit. 75 | For instance, you might wish to exclude database tests, or automatically generate 76 | HTML code coverage reports. 77 | 78 | ## Test Cases 79 | 80 | Every test needs a *test case*, or class that your tests extend. CodeIgniter 4 81 | provides a few that you may use directly: 82 | * `CodeIgniter\Test\CIUnitTestCase` - for basic tests with no other service needs 83 | * `CodeIgniter\Test\CIDatabaseTestCase` - for tests that need database access 84 | 85 | Most of the time you will want to write your own test cases to hold functions and services 86 | common to your test suites. 87 | 88 | ## Creating Tests 89 | 90 | All tests go in the **tests/** directory. Each test file is a class that extends a 91 | **Test Case** (see above) and contains methods for the individual tests. These method 92 | names must start with the word "test" and should have descriptive names for precisely what 93 | they are testing: 94 | `testUserCanModifyFile()` `testOutputColorMatchesInput()` `testIsLoggedInFailsWithInvalidUser()` 95 | 96 | Writing tests is an art, and there are many resources available to help learn how. 97 | Review the links above and always pay attention to your code coverage. 98 | 99 | ### Database Tests 100 | 101 | Tests can include migrating, seeding, and testing against a mock or live1 database. 102 | Be sure to modify the test case (or create your own) to point to your seed and migrations 103 | and include any additional steps to be run before tests in the `setUp()` method. 104 | 105 | 1 Note: If you are using database tests that require a live database connection 106 | you will need to rename **phpunit.xml.dist** to **phpunit.xml**, uncomment the database 107 | configuration lines and add your connection details. Prevent **phpunit.xml** from being 108 | tracked in your repo by adding it to **.gitignore**. 109 | -------------------------------------------------------------------------------- /tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php: -------------------------------------------------------------------------------- 1 | [ 13 | 'type' => 'varchar', 14 | 'constraint' => 31, 15 | ], 16 | 'uid' => [ 17 | 'type' => 'varchar', 18 | 'constraint' => 31, 19 | ], 20 | 'class' => [ 21 | 'type' => 'varchar', 22 | 'constraint' => 63, 23 | ], 24 | 'icon' => [ 25 | 'type' => 'varchar', 26 | 'constraint' => 31, 27 | ], 28 | 'summary' => [ 29 | 'type' => 'varchar', 30 | 'constraint' => 255, 31 | ], 32 | 'created_at' => [ 33 | 'type' => 'datetime', 34 | 'null' => true, 35 | ], 36 | 'updated_at' => [ 37 | 'type' => 'datetime', 38 | 'null' => true, 39 | ], 40 | 'deleted_at' => [ 41 | 'type' => 'datetime', 42 | 'null' => true, 43 | ], 44 | ]; 45 | 46 | $this->forge->addField('id'); 47 | $this->forge->addField($fields); 48 | 49 | $this->forge->addKey('name'); 50 | $this->forge->addKey('uid'); 51 | $this->forge->addKey(['deleted_at', 'id']); 52 | $this->forge->addKey('created_at'); 53 | 54 | $this->forge->createTable('factories'); 55 | } 56 | 57 | public function down() 58 | { 59 | $this->forge->dropTable('factories'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/_support/Database/Seeds/ExampleSeeder.php: -------------------------------------------------------------------------------- 1 | 'Test Factory', 12 | 'uid' => 'test001', 13 | 'class' => 'Factories\Tests\NewFactory', 14 | 'icon' => 'fas fa-puzzle-piece', 15 | 'summary' => 'Longer sample text for testing', 16 | ], 17 | [ 18 | 'name' => 'Widget Factory', 19 | 'uid' => 'widget', 20 | 'class' => 'Factories\Tests\WidgetPlant', 21 | 'icon' => 'fas fa-puzzle-piece', 22 | 'summary' => 'Create widgets in your factory', 23 | ], 24 | [ 25 | 'name' => 'Evil Factory', 26 | 'uid' => 'evil-maker', 27 | 'class' => 'Factories\Evil\MyFactory', 28 | 'icon' => 'fas fa-book-dead', 29 | 'summary' => 'Abandon all hope, ye who enter here', 30 | ], 31 | ]; 32 | 33 | $builder = $this->db->table('factories'); 34 | 35 | foreach ($factories as $factory) 36 | { 37 | $builder->insert($factory); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/_support/DatabaseTestCase.php: -------------------------------------------------------------------------------- 1 | mockSession(); 19 | } 20 | 21 | /** 22 | * Pre-loads the mock session driver into $this->session. 23 | * 24 | * @var string 25 | */ 26 | protected function mockSession() 27 | { 28 | $config = config('App'); 29 | $this->session = new MockSession(new ArrayHandler($config, '0.0.0.0'), $config); 30 | \Config\Services::injectMock('session', $this->session); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/database/ExampleDatabaseTest.php: -------------------------------------------------------------------------------- 1 | findAll(); 20 | 21 | // Make sure the count is as expected 22 | $this->assertCount(3, $objects); 23 | } 24 | 25 | public function testSoftDeleteLeavesRow() 26 | { 27 | $model = new ExampleModel(); 28 | $this->setPrivateProperty($model, 'useSoftDeletes', true); 29 | $this->setPrivateProperty($model, 'tempUseSoftDeletes', true); 30 | 31 | $object = $model->first(); 32 | $model->delete($object->id); 33 | 34 | // The model should no longer find it 35 | $this->assertNull($model->find($object->id)); 36 | 37 | // ... but it should still be in the database 38 | $result = $model->builder()->where('id', $object->id)->get()->getResult(); 39 | 40 | $this->assertCount(1, $result); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/session/ExampleSessionTest.php: -------------------------------------------------------------------------------- 1 | session->set('logged_in', 123); 13 | 14 | $value = $this->session->get('logged_in'); 15 | 16 | $this->assertEquals(123, $value); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/unit/HealthTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($test); 15 | } 16 | 17 | public function testBaseUrlHasBeenSet() 18 | { 19 | $env = $config = false; 20 | 21 | // First check in .env 22 | if (is_file(HOMEPATH . '.env')) 23 | { 24 | $env = (bool) preg_grep("/^app\.baseURL = './", file(HOMEPATH . '.env')); 25 | } 26 | 27 | // Then check the actual config file 28 | $reader = new \Tests\Support\Libraries\ConfigReader(); 29 | $config = ! empty($reader->baseUrl); 30 | 31 | $this->assertTrue($env || $config); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /writable/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /writable/cache/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/logs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/photo/1609648185_c4e3e1fdbd453680d53d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/writable/photo/1609648185_c4e3e1fdbd453680d53d.png -------------------------------------------------------------------------------- /writable/photo/1609648289_1b5b1dbd19d9a09eff4f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/writable/photo/1609648289_1b5b1dbd19d9a09eff4f.png -------------------------------------------------------------------------------- /writable/photo/1609648548_e1a56014f0d182122ed3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/writable/photo/1609648548_e1a56014f0d182122ed3.png -------------------------------------------------------------------------------- /writable/photo/1609648622_442519b223b274aecf6f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/writable/photo/1609648622_442519b223b274aecf6f.png -------------------------------------------------------------------------------- /writable/photoindex.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilhamlutfi/starter-ci4/98deac173b2b385de749d22a899bbbb9c84a021d/writable/photoindex.html -------------------------------------------------------------------------------- /writable/session/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/uploads/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | --------------------------------------------------------------------------------