I have too many function for database inside one model file
See my example :
<?php
namespace App\Models;
use CodeIgniter\Model;
use Medoo\Medoo;
class DBMedoo extends Model {
public $database;
public $maxfolder;
protected $session;
function __construct()
{
include APPPATH . 'ThirdParty/vendor/autoload.php';
$this->session = \Config\Services::session();
$this->session->start();
$this->database = new Medoo([
// [required]
'type' => 'mysql',
'host' => 'localhost',
'database' => 'db_testing',
'username' => 'root',
'password' => '',
// [optional]
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_general_ci',
'port' => 3306,
// [optional] Table prefix, all table names will be prefixed as PREFIX_table.
'prefix' => '',
// [optional] Enable logging, it is disabled by default for better performance.
'logging' => true,
// [optional]
// Error mode
// Error handling strategies when error is occurred.
// PDO::ERRMODE_SILENT (default) | PDO::ERRMODE_WARNING | PDO::ERRMODE_EXCEPTION
// Read more from https://www.php.net/manual/en/pdo.error-handling.php.
'error' => \PDO::ERRMODE_SILENT,
// [optional]
// The driver_option for connection.
// Read more from http://www.php.net/manual/en/pdo.setattribute.php.
'option' => [
\PDO::ATTR_CASE => \PDO::CASE_NATURAL
],
// [optional] Medoo will execute those commands after connected to the database.
'command' => [
'SET SQL_MODE=ANSI_QUOTES'
]
]);
}
public function FDatabase() {
return $this->database;
}
public function UpdatePriceAlertPush($idx) {
$this->FDatabase()->update('tb_apppricealert', [
'triggered' => 1,
'ispush' => 1,
'ipaddress' => $_SERVER['REMOTE_ADDR'],
'datetime' => date('Y-m-d H:i:s')
], [
'idx' => $idx
]);
}
include 'Ticker.php'; // Here error
include 'CheckUpdateVersion.php'; // Here error
// and 50 more.....
}
?>
How to separate each public function into every part of file and include in the main model ?
In my example above both :
include 'Ticker.php'; // Here error
include 'CheckUpdateVersion.php'; // Here error
Got error.
This is "Ticker.php"
<?php
// ================================== TICKER
function InsertTicker($array) {
$this->FDatabase()->action(function($database) use (&$array) {
$this->FDatabase()->insert('tb_ticker', [
'ticker' => $array['ticker'],
'company' => $array['company'],
'ipaddress' => $_SERVER['REMOTE_ADDR'],
'datetime' => date('Y-m-d H:i:s')
]);
// If you found something wrong, just return false value to rollback the whole transaction.
if ($this->FDatabase()->error) {
return false;
}
});
}
function SelectAllTicker() {
$Data = $this->FDatabase()->select('tb_ticker', '*');
return $Data;
}
function GetTicker($ticker) {
$Data = $this->FDatabase()->get('tb_ticker', '*', [
'ticker' => $ticker
]);
return $Data;
}
?>
and this is "CheckUpdateVersion.php"
<?php
// ================================== CHECK UPDATE VERSION
function GetUpdateVersion() {
$Data = $this->FDatabase()->get('tb_version', '*', [
'ORDER' => [
'idx' => 'DESC'
]
]);
return $Data;
}
?>
I want to separate every category function to each file. So in my model it is easy to read and find the function. Also the model will look more tidy.
Is there anyway to achieve it ? I don't want to put all public function into one file. It is too long to read and when try to use the function I need to search the name.
If I separate it into some of file base on category. Then it is easy to find and structure data may look tidy.
Remember this is codeigniter 4
Related
I'm using LDAP in my User data fixtures and I don't want to hardcode the LDAP login options. Initially, I tried this:
$options = array(
'host' => '%ldap_host%',
'port' => '%ldap_port%',
'useSsl' => true,
'username' => '%ldap_username%',
'password' => '%ldap_password%',
'baseDn' => '%ldap_baseDn_users%'
);
But that didn't work. I did some research and realized I needed to include the container in my fixtures. However, it's at this point I'm unsure what my next step is.
As I understand it I need to use the container and it's get method to get the service containing the parameters, but I don't know what that is:
$this->container->get('parameters');
Doesn't work, so I'm wondering what I should use.
My full datafixture is as follows:
class LoadFOSUsers extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
/**
* #var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function load(ObjectManager $manager)
{
$this->container->get('parameters');
// Not sure how to access param values.
$options = array(
'host' => '%ldap_host%',
'port' => '%ldap_port%',
'useSsl' => true,
'username' => '%ldap_username%',
'password' => '%ldap_password%',
'baseDn' => '%ldap_baseDn_users%'
);
$ldap = new Ldap($options);
$ldap->bind();
$baseDn = '%ldap_baseDn_users%';
$filter = '(&(&(ObjectClass=user))(samaccountname=*))';
$attributes=['samaccountname', 'dn', 'mail','memberof'];
$result = $ldap->searchEntries($filter, $baseDn, Ldap::SEARCH_SCOPE_SUB, $attributes);
foreach ($result as $item) {
echo $item["dn"] . ': ' . $item['samaccountname'][0] . PHP_EOL;
}
}
public function getOrder()
{
// the order in which fixtures will be loaded
// the lower the number, the sooner that this fixture is loaded
return 8;
}
}
You just have to fetch them from container via getParameter('name') or get them all in a bag via getParameterBag().
So:
$options = array(
'host' => $this->container->getParameter('ldap_host'),
'port' => $this->container->getParameter('ldap_port'),
'useSsl' => true,
'username' => $this->container->getParameter('ldap_username'),
'password' => $this->container->getParameter('ldap_password'),
'baseDn' => $this->container->getParameter('ldap_baseDn_users')
);
etc.
I am developing an application in CakePHP. I need two databases in same function in same controller. In Invoice I need to to add data in invoices table but need students list to show from another database having students table.
public function add() {
if ($this->request->is('post')) {
$this->Invoice->create();
$this->request->data['Invoice']['created_by'] = $this->Auth->user('id');
if ($this->Invoice->save($this->request->data)) {
$this->Session->setFlash(__('The Invoice has been saved.'), 'default', array('class' => 'alert alert-success'));
}
return $this->redirect(array('action' => 'view',$Invoice_id));
}
// fetch students from different database.
$this->loadModel('Student');
$users = $this->Student->find('list',array('fields'=>array('Student.id','Student.name')));
}
I am using the public $useDbConfig = 'fees'; as second DB configuration but unable to get the data in same function. Please help.
<?php
class DATABASE_CONFIG {
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'root',
'password' => 'admin',
'database' => 'inventory',
'prefix' => '',
//'encoding' => 'utf8',
);
// fetch students from fees controller.
public $fees = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'root',
'password' => 'admin',
'database' => 'fees',
'prefix' => '',
//'encoding' => 'utf8',
);
}
You need to declare that your Students model will use a different database source. You are saying that you used the public $useDbConfig = 'fees'; with out mentioning in which model you used this property.
Check this link
We can then configure the datasource in our app/Config/database.php
file by adding something like this:
public $faraway = array(
'datasource' => 'FarAwaySource',
'apiKey' => '1234abcd', );
Then use the database config in our models like this:
class MyModel extends AppModel {
public $useDbConfig = 'faraway';
}
So fees looks like some database that should be used on the Invoice model:
class Invoice extends AppModel {
public $useDbConfig = 'fees';
}
and Students models should most probably stay on the default database
class Students extends AppModel {
public $useDbConfig = 'default'; // This line is optional. Even if you don't write this line your model will load data from the default database.
}
Maybe the databases are the other way around but I think you got the point.
You can still configure the database source of your models from inside your Controller by doing the following:
public function add() {
...
$this->Student->useDbConfig = 'fees'
...
}
or most preferable
public function add() {
...
$this->Student->setDataSource('default')
...
}
Following is my cake console code to generate database schema. I have to manage multiple database schema migration. When I am calling generateDb function it creates a master schema after that i am switching database connection to client database, but client schema is not generating. its again generating master schema.
class HelloShell extends AppShell {
public $uses = array('ClientDbdetail');
public function generateDb() {
$runCommand = shell_exec(APP.'Console/cake schema generate -f master');
if ($runCommand) {
$sessionArray = $this->ClientDbdetail->find('first', array('recursive' => -1));
$this->__switchDb($sessionArray['ClientDbdetail']);
shell_exec(APP.'Console/cake schema generate -f client');
$this->out('Schema generated');
} else {
$this->out('Schema not generated');
}
}
private function __switchDb(array $userDetail) {
$username = 'default';
$settings = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'port' => 3306,
'login' => $userDetail['user_dbuser'],
'password' => $userDetail['user_dbpwd'],
'database' => $userDetail['user_dbname'],
'prefix' => ''
);
ConnectionManager::drop($username);
ConnectionManager::create($username, $settings);
ConnectionManager::getDataSource($username);
}
}
From CakePHP book there is an example.
public $connection = 'default';
public function before($event = array()) {
$db = ConnectionManager::getDataSource($this->connection);
$db->cacheSources = false;
return true;
}
and after :
public function before($event = array()) {
$articles = ClassRegistry::init('Articles', array(
'ds' => $this->connection
));
// Do things with articles.
}
see this : http://book.cakephp.org/2.0/en/console-and-shells/schema-management-and-migrations.html
I need to edit the dbx connection whenever needed, while the app runs.
I have defined 2 db connection settings;
db is for the central db
dbx is for any other slave db (my app has a slave db for each user)
for each user, the dbx has its own username and password, wich will be saved in a db table;
'db' => array(
'connectionString' => 'mysql:host=localhost;dbname=dvc',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
),
'dbx' => array(
'connectionString' => 'mysql:host=localhost;dbname=dvc2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'tablePrefix' => '',
'class' => 'CDbConnection' // DO NOT FORGET THIS!
),
I think, you may not configuring dbx on configs and after user login creates it component with needed params before any using dbx in code. You can do it by (describes here):
Yii::app()->createComponent('dbx', array(
'connectionString' => 'mysql:host=localhost;dbname=dvc2',
'username' => <user db login>,
'password' => <user db pass>,
'charset' => 'utf8',
'tablePrefix' => '',
'class' => 'CDbConnection' // DO NOT FORGET THIS!
))
For removing existing component you can do Yii::app()->createComponent('dbx', null) and then create this component with other's parameters
so, the tested solution is:
<?php
class DomainSlaveM extends Domain {
public static function model($className = __CLASS__) {
return parent::model($className);
}
public static $server_id = 1;
public static $slave_db;
public function getDbConnection() {
self::$slave_db = Yii::app()->dbx;
if (self::$slave_db instanceof CDbConnection) {
$config = require(Yii::app()->getBasePath() . '/config/location/setting.php');
$connectionString = 'mysql:host=localhost;dbname=irdb' . self::$server_id;
self::$slave_db->connectionString = sprintf($connectionString, 'dbx');
self::$slave_db->setActive(true);
return self::$slave_db;
}
else
throw new CDbException(Yii::t('yii', 'Active Record requires a "db" CDbConnection application component.'));
}
}
and the code is:
DomainSlaveM::$server_id = 1;
$model_domain_slave_m = DomainSlaveM::model()->findByAttributes(array('id' => 1));
if ($model_domain_slave_m) {
$model_domain_slave_m->updated = time();
if ($model_domain_slave_m->validate() && $model_domain_slave_m->save()) {
}
}
original article found at:click here
I'm really confused!
I'm a beginner with ZF2. Starting to discover it now.
I've followed Starting Skeleton application at Zend manuals.
The problem there is that for creating Album module it only uses one table that is impossible in real world. When developing one will have several tables at least.
now I'm reading Web Development with ZF2 by Michael Romer.
The thing is that I can't really understand where did he put his code.
According to the book - he puts his code inside module.config.php
<?php
$dbParams = array(
'database' => 'gott',
'username' => 'root',
'password' => '',
'hostname' => 'localhost',
);
return array(
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => function ($sm) use ($dbParams) {
return new Zend\Db\Adapter\Adapter(array(
'driver' => 'pdo',
'dsn' => 'mysql:dbname='.$dbParams['database'].';host='.$dbParams['hostname'],
'database' => $dbParams['database'],
'username' => $dbParams['username'],
'password' => $dbParams['password'],
'hostname' => $dbParams['hostname'],
));
},
),
),
);
and when I look at the code at GitHub, it says it should be in global.php inside config/autoload.
As I understand, the idea is - we have params and some setup inside global.php, then we detect service started by global.php in module.config.php (with the code below) and assign it to controller:
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
'Portfolio\Mapper\Category' => function($sm){
return new \Portfolio\Mapper\Category($sm->get('Zend\Db\Adapter\Adapter'));
}
),
),
So as far as I understand now my controller should be able to detect my DB connection.\
This is my controller code
public function addCategoryAction(){
$form = new \Portfolio\Form\CategoryAdd();
if($this->getRequest()->isPost()){
$form->setHydrator(new \Zend\Stdlib\Hydrator\Reflection());
$form->bind(new \Portfolio\Entity\Category());
$form->setData($this->getRequest()->getPost());
if($form->isValid()) {
$newEntity = $form->getData();
$mapper = $this->getServiceLocator()->get('Portfolio\Mapper\Category');
$mapper->insert($newEntity);
$form = new \Portfolio\Form\CategoryAdd();
return new ViewModel(array(
'form' => $form,
'success' =>true
));
} else {
return new ViewModel(array(
'form' => $form
));
}
} else {
return new ViewModel(array(
'form' => $form
));
}
// $viewObject = new ViewModel(array(
// 'form' => $form
// ));
// return $viewObject;
}
And here's my Mapper with TableGateway
<?php
namespace Portfolio\Mapper;
use Portfolio\Entity\Category as CategoryEntity;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\TableGateway\Feature\RowGatewayFeature;
class Category extends TableGateway {
protected $tableName = 'portfolio_categories';
protected $idCol = 'categoryId';
protected $entityPrototype = null;
protected $hydrator = null;
public function __construct($adapter){
parent::__construct($this->tableName, $adapter, new RowGatewayFeature($this->idCol));
$this->entityPrototype = new CategoryEntity();
$this->hydrator = new \Zend\Stdlib\Hydrator\Reflection;
}
public function insert($entity){
return parent::insert($this->hydrator->extract($entity));
}
}
It's not working.
An error occurred
An error occurred during execution; please try again later.
Additional information:
Zend\Db\Adapter\Exception\InvalidQueryException
File:
F:\Server\htdocs\gott\vendor\ZF2\library\Zend\Db\Adapter\Driver\Pdo\Statement.php:245
Message:
Statement could not be executed
Can you tell me the right way to do it and the idea how it should work?
Thank you!