I've created a DataSource for connecting to a WSDL server and post/get data.
But, I don't know how to use it in a controller? with a MySQL database (I mean I need both of them, a soap and a database is needed.)
If I put this in my model, it will use my datasource; but I think it won't use its mysql table...:
public $useTable = false;
public $useDbConfig = 'mydatasource';
How?
You can use $this->Modelname->setDataSource('default') and setDataSource('mydatasource') to switch between the two sources on the fly.
But you also need to change between using a table, and not using a table, i use the following code to switch between a no-table source, and mysql:
public $oldSource = array();
public function setDbConfig($source = null, $useTable = null) {
$ds = $this->getDataSource();
if (method_exists($ds, 'flushMethodCache')) {
$ds->flushMethodCache();
}
if ($source) {
$this->oldSource = array('useTable' => $this->useTable, 'useDbConfig' => $this->useDbConfig);
$this->setDataSource($source);
if ($useTable !== null) {
$this->setSource($useTable);
}
} else {
if ($this->oldSource) {
$this->setDataSource($this->oldSource['useDbConfig']);
$this->setSource($this->oldSource['useTable']);
$this->oldSource = array();
}
}
}
Related
I am having issues with a Laravel application using an existing database where MS SQL UUIDs are used. My application has a customer:
class Customer extends Model
{
protected $table = 'ERP.Customer';
public $timestamps = false;
protected $primaryKey = 'CustID';
protected $keyType = 'string';
protected $fillable = [
'CustID',
'SysRowID',
'CustNum',
'LegalName',
'ValidPayer',
'TerritoryID',
'Address1',
'Address2',
'Address3',
'City',
'State',
'Zip',
'Country',
'SalesRepCode',
'CurrencyCode',
'TermsCode',
'CreditHold',
'FaxNum',
'PhoneNum',
'CustomerType'
];
public function SalesTer()
{
return $this->belongsTo(SalesTer::class,'TerritoryID', 'TerritoryID');
}
public function Shipments()
{
return $this->hasMany(Shipment::class, 'CustNum', 'CustNum');
}
public function Equipments()
{
return $this->hasMany(Equipment::class,'CustNum', 'CustNum');
}
public function Customer_UD()
{
return $this->hasOne(Customer_UD::class,'ForeignSysRowID', 'SysRowID');
}
}
Which (in the native ERP application) has a UD table which end users can used to customise the Customer entity:
class Customer_UD extends Model
{
protected $table = 'ERP.Customer_UD';
protected $primaryKey = 'ForeignSysRowID';
public $timestamps = false;
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = [
'ForeignSysRowID',
'MakesCans_c',
'MakesEnds_c',
'Industry_c'
];
public function Customer()
{
return $this->hasOne(Customer::class,'SysRowID', 'ForeignSysRowID');
}
}
CustomerController:
public function show($CustID)
{
if(Customer::find($CustID))
{
$Customer = Customer::find($CustID);
$Customer_UD = $Customer->Customer_UD()
->get();
$Shipments = $Customer->Shipments()
->where('Voided', '0')
->get();
$Equipments = $Customer->Equipments()
->with('Part') // load the Part too in a single query
->where('SNStatus', 'SHIPPED')
->get();
return view('Customer.show', ['NoCust' => '0'],
compact('Equipments', 'Customer','Shipments', 'Parts', 'Customer_UD'));
}
else
{
return view('Customer.show', ['NoCust' => '1']);
}
}
The Customer has (for whatever reason) a CustID (which people use to refer to the customer) a CustNum (which is not used outside of the database and a SysRowID. The SysRowID is used to link the Customer table with the Customer_UD table.
An example row from Customer_UD is:
My issue is that when trying to return the UD fields along with the Customer fields I get an error:
SQLSTATE[HY000]: General error: 20018 Incorrect syntax near ''.
[20018] (severity 15) [select * from [ERP].[Customer_UD] where [ERP].
[Customer_UD].[ForeignSysRowID] = '���_�X�O�Q3�^w' and [ERP].
[Customer_UD].[ForeignSysRowID] is not null]
I thought it was odd, so I commended out the Customer_UD lines in the CustomerController and simply tried to display the Customer UUID field in the show blade:
SysRowID: {{$Customer->SysRowID}}
I get nothing, no errors but no data. I created a controller and index blade for the Customer_UD model and can display all of the Customer_UD database fields apart from the UUID field.
I don't actually want to display the UUID fields - but do need to use them to build the relationships. Can anyone help point me in the right direction?
I found that adding:
'options' => [
PDO::DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER => true,
],
To the database configuration in config\database.php resolved the issue.
I'm trying to force my app to check every time it loads a model or controller depending on which is my session value.
This is actually running, but just when I get throw this model.
class News_model extends CI_Model {
public function __construct()
{
parent::__construct();
if($this->session->dbname=='db1'){
$this->db=$this->load->database('db1', TRUE);
}
else{
$this->db=$this->load->database('db2', TRUE);
}
}
public function get_news($slug = FALSE)
{
if ($slug === FALSE)
{
$query = $this->db->get('news');
return $query->result_array();
}
$query = $this->db->get_where('news', array('slug' => $slug));
return $query->row_array();
}
}
But I do not war to include that __construct code to all my models or controllers.
I've tried to add on my autoload.php
$autoload['model'] = array('General');
Where my General code is something like this.
class General extends CI_Model {
function __construct()
{
parent::__construct();
if($this->session->dbname=='db1'){
$this->db=$this->load->database('db1', TRUE);
}
else{
$this->db=$this->load->database('db2', TRUE);
}
}
}
How can I do it?
You can do it by creating a base model which will be extended by your models that require the database check.
I have simplified the checking and loading code. A simple ternary determines the string to use and stores it in the variable $dbname. That variable is used to load the database, i.e. $this->load->database($dbname);.
I don't believe you need the second argument to load::database() which means you don't need to set $this->db explicitly. If I'm wrong, use
$this->db = $this->load->database($dbname, TRUE);
Below is the "base" model. The prefix of the file name is determined in config.php with the setting $config['subclass_prefix'] = 'MY_'; Adjust your base model's file and class name to match the 'subclass_prefix' you use.
/application/core/MY_Model.php
<?php
class MY_Model extends CI_Model
{
public function __construct()
{
parent::__construct();
$dbname = $this->session->dbname == 'db1' ? 'db1' : 'db2';
$this->load->database($dbname);
}
}
Use the above to create other models like so...
class News_model extends MY_Model
{
public function get_news($slug = FALSE)
{
if ($slug === FALSE)
{
$query = $this->db->get('news');
return $query->result_array();
}
$query = $this->db->get_where('news', array('slug' => $slug));
return $query->row_array();
}
}
I want to insert multiple record in my table using yii2 ActiveRecord.
I already know that I can use this code
$connection->createCommand()->batchInsert('user', ['name', 'age'], [
['Tom', 30],
['Jane', 20],
['Linda', 25],
])->execute();
but by this approach my model validations are not executing.
and I already have read this question
ActiveRecord batch insert (yii2)
but also by doing validation in a tricky way, consider I want to fill created_at and updated_at columns using ActiveRecords events.
just like this
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if($insert)
$this->created_at = date('Y-m-d H:i:s');
$this->updated_at = date('Y-m-d H:i:s');
return true;
} else {
return false;
}
}
I think is not good idea to use beforeSave events (and similar stuff) because it will trigger for each model. However you want save multiple models at once. I recommend to use bulk methods.
In similar cases I use usually following "bulk" approach (code not tested, just for example):
namespace common\components;
class Model extends yii\base\Model {
/**
* Saves multiple models.
*
* #param ActiveRecord[] $models
* #return bool
*/
public static saveMultiple($models){
if(count($models) > 0){
$firstModel = reset($models);
$columnsToInsert = $firstModel->attributes(); // here you can remove excess columns. for example PK column.
$modelsToInsert = [];
$rowsToInsert = [];
foreach($models as $model){
if ($this->beforeSave(true)) {
$modelsToInsert[] = $model;
}
}
foreach($modelsToInsert as $model){
$rowsToInsert[] = array_values($model->attributes); // here you can remove excess values
}
$numberAffectedRows = \Yii::$app->db->createCommand()
->batchInsert($firstModel->tableName(), $columnsToInsert, $rowsToInsert)
->execute();
$isSuccess = ($numberAffectedRows === count($models));
if($isSuccess){
$changedAttributes = array_fill_keys($columnsToInsert, null);
foreach($modelsToInsert as $model){
$model->afterSave(true, $changedAttributes);
}
}
return $isSuccess;
} else {
return true;
}
}
}
This class can be used:
use common\components\Model;
/**
* #var SomeActiveRecord[] $models Array that contains array of active records (type SomeActiveRecord)
*/
// ...
if (Model::validateMultiple($models)){
if(!Model::saveMultiple($models)){
// ... some error handling
}
} else {
foreach($models as $model){
if($model->hasErrors()){
$errors = $model->getFirtsErrors();
// ... some error handling
}
}
}
Additionally, for more convenient working with multiple models can be developed special Collection class that implements \ArrayAccess and \Iterator interfaces. This collection can iterated as simple array, however it contains special methods for bulk operations. Something like this:
foreach($modelCollection as $model){
// ...
}
$modelCollection->validate(); // works similar to common\components\Model::validateMultiple()
$modelCollection->save(); // works similar to common\components\Model::saveMultiple()
I'm searching for a better PDO db connection which I could use in the different classes I have. For example my current code is like this:
core.php
//Connecting to Database
try {
$db = new PDO("mysql:host=localhost;dbname=mydb", "project", "project123");
}
catch(PDOException $e) {
echo $e->getMessage();
}
class Core {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
function redirectTo($page,$mode = 'response',$message = '') {
if($message != '') {
header('Location: '.SITEURL.'/'.$page.'?'.$mode.'='.urlencode($message));
} else {
header('Location: '.SITEURL.'/'.$page);
}
exit();
}
}
And apart from this I have 2 more class: wall.php and ticker.php
class Wall {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
function addComment($uid, $fid, $comment) {
$time = time();
$ip = $_SERVER['REMOTE_ADDR'];
$query = $this->db->prepare('INSERT INTO wall_comments (comment, uid_fk, msg_id_fk, ip, created) VALUES (:comment, :uid, :fid, :ip, :time)');
$query->execute(array(':comment' => $comment, ':uid' => $uid, ':fid' => $fid, ':ip' => $ip, ':time' => $time));
$nofity_msg = "User commented on the post";
$setTicker = Ticker::addTicker($uid,$nofity_msg,'comment');
if($setTicker) {
Core::redirectTo('wall/view-'.$fid.'/','error','Oops, You have already posted it!');
} else {
Core::redirectTo('wall/view-'.$fid.'/','error','Oops, Error Occured');
}
}
}
and ticker.php is:
class Ticker {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
function addTicker($uid,$msg,$type) {
$time = time();
$query = $this->db->prepare('INSERT INTO tickers (uid_fk, message, type, created) VALUES (:uid, :message, :type, :time)');
try {
$query->execute(array(':uid' => $uid, ':message' => $msg, ':type' => $type, ':time' => $time));
return $this->db->lastInsertId();
}
catch(PDOException $e) {
return 0;
}
}
}
Now my problem is that I need to call for the function addComment() and inside that function there is a further call for the function addTicker() present in the class Ticker. This is causing a Db connection problem as there is already an db instance created in the previous class or so.. I can't figure out how to sort this out.
This is the code I'm using in the main index file:
$core = new Core($db);
$ticker = new Ticker($db);
$wall = new Wall($db);
$wall->addComment($uid, $fid, $add_comment); // This statement is not working.. :(
My intention is to have a common main DB connection and further use that connection in other classes. Is there any better way to do it..?
there is already an db instance created in the previous class
this is actually single instance, but copied into 2 variables.
This is causing a Db connection problem
Can you please be a bit more certain about such a problem? What particular problem you have?
Hello guys im using WCF RIA Services i have domain services where i wrote this method
public List<int> GetActionIDs()
{
return (from d in ObjectContext.actions select d.id).ToList();
}
How i can get this List in client side?
This does not works :
List<int> = db.GetActionIDs();
any suggestions?
First of all, you should read the RIA Services manual, because you don't realize that service calls in Silverlight are asynchronous.
In your case, you should
Add InvokeAttribute to your operation in the service:
[Invoke]
public List<int> GetActionIDs()
{
return (from d in ObjectContext.actions select d.id).ToList();
}
Then, all calls to DomainContext are asynchronous, so you get your results in the callback:
db.GetActionIDs(operation =>
{
//TODO: check the operation object for errors or cancellation
var ids = operation.Value; // here's your value
//TODO: add the code that performs further actions
}
, null);
inside DomainSrvice
[Query]
public List<Action> GetActionIDs()
{
List<Action> result = (
from a in ObjectContext.actions
select new action
{
ID = a.ID
}
).ToList();
return result ;
}
Silverlight
DomainService1 DS = new DomainService1();
LoadOperation<Action> LoadOp = Ds.Load(Ds.GetActionIDsQuery());
LoadOperation.Completed += new EventHandler((s,e)=>{
foreach (Action item in LoadOp.Entities)
{
}
});