How do I implement a model for an Oracle package in CakePHP? - cakephp

I have an Oracle package that I need to access in CakePHP. I am trying to determine the best way to implement the code for calling this function. I need to pass for variables from the UI to the procedure being called. I want to be able to use the model for the field validation before submitting to the package. It is a very specific procedure call:
begin SCHEMA.package.function_name(vars); end;
At the same time, there isn't the standard $this->save() or $this->find() to a package.
Does anyone have CakePHP experience with this? Or any suggestions for implementation? Should I just put it in a model by itself?

Well, after no response I did some digging this week, and I think I have a great solution to this. I was actually thinking it was more complicated than what it really is.
Set up a model to point to the package you create. Within the package there may be multiple functions. So the model will contain all of the functions for the package that are required for your application.
Here is what my model looks like:
<?php
class {PACKAGENAME} extends AppModel {
var $name = {PACKAGENAME};
var $useTable = false;
function {PACKAGE_METHOD}() {
return $this->query('begin SCHEMA.PACKAGE.FUNCTION(); end;');
}
}
Replace the {PACKAGENAME} with the name of the Oracle package. The rest should be self explanatory. You can also configure the function to handle variables, of course.

Related

How to create a whitelist of updatable fields in a CakePHP's model?

I want to create a whitelist of fields that I want to be updatable in CakePHP. I know that I can pass a fieldList array in the call to Model::save(), but this isn't what I'm looking for. What I want is that every model "publish" a list of the valid fields, so if I call the Model::save() method without a fieldList and with data that mustn't be updatable (like the ownerId) this won't be updated.
What can I do to get this behavior? Maybe override the Model::save method in every Model to call at the "original" Model::save with the whitelist? I think this is a good idea, because I don't pollute all the controllers with lots of duplicated whitelists...
Thanks for your help!
Well, thanks you all for your answers, but I was wrong: I don't need to add this functionality.
The problem I was trying to solve was a security problem, I was trying to avoid form tampering (I've discovered the name just now), and as I am a novice CakePHP user, I didn't know that CakePHP already manages this problem.
The answer to my question is very easy: I must use CakePHP's Security Plugin and use the Form Tampering prevention (http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#form-tampering-prevention).
Can‘t say I’ve ever needed to do this in CakePHP, but CakePHP only saves the fields you pass it.
If you really need to create a white-list and you’re certain you only ever want these fields saving and never any others in your database (although I don’t understand why you have columns for them if you never touch them) then you could emulate this behavior in a model callback method:
<?php
class User extends AppModel {
public function beforeSave($options = array()) {
$whitelist = array('first_name', 'last_name', 'email');
foreach ($this->data[$this->alias] as $field => $value) {
if (!in_array($field, $whitelist)) {
unset($this->data[$this->alias][$field]);
}
}
return true;
}
}
This will just unset any data not in the $whitelist array, but if you really don’t want a column being updated then don’t pass a value for it.

Howto extend a plugin model class in CakePHP with "clean" classnames?

I'm currently learning CakePHP. I use CakePHP 2.2.3. I have succesfully "installed" a user management plugin. This plugin has a model class "User" and uses table "users". Now, I'd like to extend this User model in order to e.g. relate my own models to it, e.g. Posts.
I managed to to this with the following code:
App::import('Model', 'Usermgmt.User');
class MyUser extends User {
var $hasMany = array('Post');
var $useTable = 'users';
}
This works.
However, I don't like the fact that I have to call my Model class something like "MyUser". It makes everything very ugly and, maybe - theoretically - sometime I want to install another plugin that uses classname "MyUser". Is it somehow possible to use "clean" class names and prevent possible name collisions in the future..?
No, that's not possible because CakePHP doesn't yet support namespaces. According to the roadmap support for namespaces is planned for CakePHP 3.

Dynamically passing a model name to a CakePHP Plugin

I'm having trouble wording my problem, so it's been tough to search for an answer. Hopefully you'll know how to help.
I am creating a CakePHP 2.1 Plugin that will interact with a series of its own Models:
- Friend
- Group
- User
Friend and Group are models that are created specifically for the Plugin, and they function within the plugin normally. However, the User model is really just an alias for some other table in the parent app.
So, if "My Awesome Application" decides to use "My Awesome Plugin", it will have to have its own "users" table (though it may called something else). Let's say "My Awesome Application" has a Model called MyUser. "My Awesome Plugin" wants to dynamically tell its internal User model to $useTable = "my_users".
My question is, how do I pass that data to the Plugin? How do I configure "My Awesome Plugin" to understand that User should $useTable "my_users";
As I understand you would like a Model in a PlugIn to use a table that would typically belong to a Model in your Application - by the conventions. Have you tried statically setting:
public $useTable = "my_users";
in the plugin? All plugins usually get initialized when Cake starts up, so all configurations should be loaded then. Why do you need this - it does really restrict you a lot? Will the table being used by the Plugin model change runtime?
The Model class also has some goodies you may find useful:
$this->User->table;
holds the table name for the model - the table that is currently being used that is**.
Also you can set the source table for the Model (inside a Controller) with:
$this->User->setSource('table_name);
** I am not sure if this applies when you use Model::setSource(). It would be interesting to check out what $this->User->table; holds after a Model::setSource() call.
I've figured out a way to accomplish this, but it might not work in all scenarios for all people.
I created a Component in my Plugin, and then I call the Component in my Controller. I pass the name of the users Model through the Component. This way, I can get information about the users Model, and I can set it as the useTable to my Plugin for use in the Plugin.
Of course, this method restricts me to using the Component to utilize the Plugin, but that's probably for the best.
Here's an example of how I did it:
// in the AppController
public $components = array(
'MyPlugin.MyPluginComponent' => array('userModel'=>'UserModelName')
);
// in the Plugin's Component
class MyPluginComponent extends Component {
function initialize($controller) {
//get the base user model
$this->UserModel = ClassRegistry::init($this->settings['userModel']);
//set the useTable for our plugin's user model
$this->PluginUser = ClassRegistry::init('MyPlugin.PluginUser');
//set the useTable value for this model
$this->PleaseUser->setSource($this->UserModel->useTable);
}
That seems to work for me. Hope this helps someone else.

How do I associate a database table with a model in ATK?

I have legacy code which stores temporary data in the context. I would like to store this in the DB using the following model:
class Model_MyModel extends Model_Table {
function init(){
parent::init();
$this->addField('myString');
}
}
I can access the data from within the legacy Controller thus:
class Controller_LegacyController extends Controller {
$myString = $this->api->recall("legacyString");
}
But I can't see how to tie everything together (all the examples use a Form to link to the DB)
Thanks for your help,
Greg.
I find your question and code a bit confusing, but I'll try to help.
You don't need controller to be able to use your model. When calling $form->setModel() it automatically pick the right controller for you.
$page->add('MVCForm')->setModel('MyModel');
When you want to send data back into data-base, you should call $form->update(). There is a View you can use, which will do that for you called: FormAndSave
$page->add('FormAndSave')->setModel('MyModel'); // will also save data back to database.
If you load data from database, you need to call loadData() on the model. Your final code might look like this (stickyGET ensures that it pass get argument inside form submit handler):
$this->api->stickyGET('id');
$page->add('FormAndSave')->setModel('MyModel')->loadData($_GET['id']);
method recall() deals with sessions, so it seems as if you are reading data from the session. If you intend that and you want to see value of your session variable in the form, then this will do it:
$form->set('myfield',$this->api->recall('legacyString'));
I hope this will give you some hints on how to continue. Look through more samples, there are lots of them on http://agiletoolkit.org

Insert/save client search/form entries into separate table prior to running code- CakePHP

I want to store the form entries into a table that will store what my users searched for, then actually execute the code on the form results.
I tried doing:
$this->Search->create();
$this->Search->save($this->data);
But I don't think it liked me using a model that doesn't belong to that controller (my guess this doesn't follow convention and fully utilize CakePHP).
The other idea I had was to create a new searches_controller, then run $this->data through the above code and redirect back to the Trips controller but it seems like that's not the optimal way of doing it either.
Any thoughts on how best to do this?
In procedural PHP, I would just do an INSERT query before.
Thanks for the help!
I think that having Model which doesn't belong to the specific controller is not so bad idea.
Actually you can put this logic in the beforeFilter() of the Trips model like that:
class Trip extends AppModel {
//....
function beforeFind(){
if($this->data){
$search = ClassRegistry::init('Search'); //adding instance of Search model
$search->save($this->data); //save the data
//Do extra things if needed
}
}
//....
}
This way you don't have "alien" model in your controllers, and utilise the recommendation "Fat Models, Skinny controllers" :)

Resources