[HMVC??] Call Functions in another controller and get values - kohana-3

I am facing a situation where I need to call a function to check some status.
$lastupdate=Request::factory('user/getlastupdate/'.$userid.'')->execute();
My getlastupdate function looks like this:
public function action_getlastupdate($userid){
$status=array();
try{
$updatestatus= ORM::factory('updates')
->where('id', '=', $userid)
->where('deleted', '=',0)
->find_all();
//check if result returned values
$resultcount=count($updatestatus);
//if result has data
if($resultcount>0){
foreach($updatestatus as $status)
{
$stat="found";
$result= 'Profile Last Updated on'.$updatestatus->lastupdate;
}
}//end if result has data
//if record returned no values
else{
$stat="missing";
$result= 'Profile Data Missing';
}//end if resultcount>0
}//end try
catch(ORM_Validation_Exception $e)
{
$stat="error";
$result="Profile Update Search Error ".$e->errors('updates');
}///end catch
$status['result']=$result;
$status['stat']=$stat;
$this->response->body(View::factory('pages/updatestatus', $status));
}//end function
This works but I do not want to render the view. I want to return the array status and use it from within my controller which is calling this method. How can I implement this? Does the code change if I call from the same controller vis a vis calling from a different controller?
I am using kostache templates so I need to play with the status[values] before rendering final output to my view.

You could send an extra parameter for your subquery which will indicate whether to auto render the view or not.
$lastupdate=Request::factory('user/getlastupdate/'.$userid.'/off')->execute();
and in your action getlastupdate check the parameter
action_getlastupdate($userid, $renderView = '')
{
if( $renderView === 'off' )
{
$this->auto_render = FALSE;
}
[...]
}

Related

React Native: Reach-Navigation and Pouch-DB - db.put not done before "refresh" callback is run

Relative newbie; forgive me if my etiquette and form here aren't great. I'm open to feedback.
I have used create-react-native-app to create an application using PouchDB (which I believe ultimately uses AsyncStorage) to store a list of "items" (basically).
Within a TabNavigator (main app) I have a StackNavigator ("List screen") for the relevant portion of the app. It looks to the DB and queries for the items and then I .map() over each returned record to generate custom ListView-like components dynamically. If there are no records, it alternately displays a prompt telling the user so. In either case, there is an "Add Item" TouchableOpacity that takes them to a screen where they an add a new item (for which they are taken to an "Add" screen).
When navigating back from the "Add" screen I'm using a pattern discussed quite a bit here on SO in which I've passed a "refresh" function as a navigation param. Once the user uses a button on the "Add" screen to "save" the changes, it then does a db.post() and adds them item, runs the "refresh" function on the "List screen" and then navigates back like so:
<TouchableOpacity
style={styles.myButton}
onPress={() => {
if (this.state.itemBrand == '') {
Alert.alert(
'Missing Information',
'Please be sure to select a Brand',
[
{text: 'OK', onPress: () =>
console.log('OK pressed on AddItemScreen')},
],
{ cancelable: false }
)
} else {
this.createItem();
this.props.navigation.state.params.onGoBack();
this.props.navigation.navigate('ItemsScreen');
}
}
}
>
And all of this works fine. The "refresh" function (passed as onGoBack param) works fine... for this screen. The database is called with the query, the new entry is found and the components for the item renders up like a charm.
Each of the rendered ListItem-like components on the "List screen" contains a react-native-slideout with an "Edit" option. An onPress for these will send the user to an "Item Details" screen, and the selected item's _id from PouchDB is passed as a prop to the "Item Details" screen where loadItem() runs in componentDidMount and does a db.get(id) in the database module. Additional details are shown from a list of "events" property for that _id (which are objects, in an array) which render out into another bunch of ListItem-like components.
The problem arises when either choose to "Add" an event to the list for the item... or Delete it (using another function via [another] slideout for these items. There is a similar backward navigation, called in the same form as above after either of the two functions is called from the "Add Event" screen, this being the "Add" example:
async createEvent() {
var eventData = {
eventName: this.state.eventName.trim(),
eventSponsor: this.state.eventSponsor.trim(),
eventDate: this.state.eventDate,
eventJudge: this.state.eventJudge.trim(),
eventStandings: this.state.eventStandings.trim(),
eventPointsEarned: parseInt(this.state.eventPointsEarned.trim()),
};
var key = this.key;
var rev = this.rev;
await db.createEvent(key, rev, eventData);
}
which calls my "db_ops" module function:
exports.createEvent = function (id, rev, eventData) {
console.log('You called db.createEvent()');
db.get(id)
.then(function(doc) {
var arrWork = doc.events; //assign array of events to working variable
console.log('arrWork is first assigned: ' + arrWork);
arrWork.push(eventData);
console.log('then, arrWork was pushed and became: ' + arrWork);
var arrEvents = arrWork.sort((a,b)=>{
var dateA = new Date(a.eventDate), dateB = new Date(b.eventDate);
return b.eventDate - a.eventDate;
})
doc.events = arrEvents;
return db.put(doc);
})
.then((response) => {
console.log("db.createEvent() response was:\n" +
JSON.stringify(response));
})
.catch(function(err){
console.log("Error in db.createEvent():\n" + err);
});
}
After which the "Add Event" screen's button fires the above in similar sequence to the first, just before navigating back:
this.createEvent();
this.props.navigation.state.params.onGoBack();
this.props.navigation.navigate('ItemsDetails');
The "refresh" function looks like so (also called in componentDidMount):
loadItem() {
console.log('Someone called loadItem() with this.itemID of ' + this.itemID);
var id = this.itemID;
let totalWon = 0;
db.loadItem(id)
.then((item) => {
console.log('[LOAD ITEM] got back data of:\n' + JSON.stringify(item));
this.setState({objItem: item, events: item.events});
if (this.state.events.length != 0) { this.setState({itemLoaded: true});
this.state.events.map(function(event) {
totalWon += parseInt(event.eventPointsEarned);
console.log('totalWon is ' + totalWon + ' with ' +
event.eventPointsEarned + ' having been added.');
});
};
this.setState({totalWon: totalWon});
})
.catch((err) => {
console.log('db.loadItem() error: ' + err);
this.setState({itemLoaded: false});
});
}
I'm at a loss for why the List Screen refreshes when I add an item... but not when I'm doing other async db operations with PouchDB in what I think is similar fashion to modify the object containing the "event" information and then heading back to the Item Details screen.
Am I screwing up with Promise chain someplace? Neglecting behavior of the StackNavigator when navigating deeper?
The only other difference being that I'm manipulating the array in the db function in the non-working case, whereas the others I'm merely creating/posting or deleting/removing the record, etc. before going back to update state on the prior screen.
Edit to add, as per comments, going back to "List screen" and the opening "Item Details" does pull the database data and correctly shows that the update was made.
Further checking I've done also revealed that the console.log in createEvent() to print the response to the db call isn't logging until after some of the other dynamic rendering methods are getting called on the "Item Details" screen. So it seems as though the prior screen is doing the get() that loadItem() calls before the Promise chain in createEvent() is resolving. Whether the larger issue is due to state management is still unclear -- though it would make sense in some respects -- to me as this could be happening regardless of whether I've called my onGoBack() function.
Edit/bump: I’ve tried to put async/await to use in various places in both the db_ops module on the db.get() and the component-side loadItem() which calls it. There’s something in the timing of these that just doesn’t jive and I am just totally stuck here. Aside from trying out redux (which I think is overkill in this particular case), any ideas?
There is nothing to do with PDB or navigation, it's about how you manage outer changes in your depending (already mounted in Navigator since they are in history - it's important to understand - so componentDidMount isn't enough) components. If you don't use global state redux-alike management (as I do) the only way to let know depending component that it should update is passing corresponding props and checking if they were changed.
Like so:
//root.js
refreshEvents = ()=> { //pass it to DeleteView via screenProps
this.setState({time2refreshEvents: +new Date()}) //pass time2refreshEvents to EventList via screenProps
}
//DeleteView.js
//delete button...
onPress={db.deleteThing(thingID).then(()=> this.props.screenProps.refreshEvents())}
//EventList.js
...
constructor(props) {
super(props);
this.state = {
events: [],
noEvents: false,
ready: false,
time2refreshEvents: this.props.screenProps.time2refreshEvents,
}
}
static getDerivedStateFromProps(nextProps, currentState) {
if (nextProps.screenProps.time2refreshEvents !== currentState.time2refreshEvents ) {
return {time2refreshEvents : nextProps.screenProps.time2refreshEvents }
} else {
return null
}
}
componentDidMount() {
this._getEvents()
}
componentDidUpdate(prevProps, prevState) {
if (this.state.time2refreshEvents !== prevState.time2refreshEvents) {
this._getEvents()
}
}
_getEvents = ()=> {
//do stuff querying db and updating your list with actual data
}

Protractor: Is it possible to check if an element doesn't contain certain text?

On the page that I am testing, a user can have a single currency or multiple currencies (i.e EUR and USD)the currency/currencies will appear in the same div at the top of the page.
If a user has multiple currencies, a tab for each currency will appear further down the page, if a user has only one currency, no tabs will appear (as there is no need for the user to switch tabs).
I am able to test multi currency users by checking to see if the text contained in the header matches the text contained in the currencies tabs.
However, as no tabs appear for a single currency, I'm not sure how to test this.
For example, if I have only a 'EUR' currency, is there a way to do something like
if element(by.className("currencies"))contains 'EUR'
&& doesn't contain 'USD' && doesn't contain 'GBP'
expect element(by.className("tabs").toDisplay.toBeFalsy()
This is the code for the page object file
this.checkCurrency = function(currency) {
var checkBalance = element(by.className("balances"));
checkBalance.getText().then(function (text) {
if (text.indexOf("GBP" && "EUR")>= 0) {
expect(element.all(by.linkText("GBP")).isDisplayed()).toBeTruthy();
console.log("EUR GBP buyer");
}
else if (text.indexOf("GBP" && "USD")>= 0) {
expect(element.all(by.linkText('USD')).isDisplayed()).toBeTruthy();
console.log("USD GBP buyer");
}
else
{
console.log("false");
}
});
};
From your description I'm not quite sure where the failure is. In general you want to keep this kind of logic out of your page object. Your test should understand what state the page should be in and call different functions. I know that's not always possible, but it works out so much better if you can. Here is some general condition advise that should help.
You can catch the success state and a failed state of a promise. Most people use the pass function, but forget about the fail function.
promise.then(passFunction, failFunction)
You can use this in several different ways. If you realize that almost everything in protractor is returning a promise.
Example:
element(by.className("currencies")).getText()
.then(
function(text) {
//check on something
},function(error){
//don't check on something
if(someCondition) {
throw error;
} else {
//the test continues
}
});
You can even do it with and expect
expect(element(by.className("currencies")).getText()).not.toContain("EUR")
.then(
function(passed) {
//check on something
},function(failed){
//don't check on something
if(someCondition) {
throw failed;
} else {
//the test continues
}
});
Or a simple findElement
element(by.className("currencies"))
.then(
function(element) {
//check on something
},function(error){
//don't check on something
if(someCondition) {
throw failed;
} else {
//the test continues
}
});

How to display flash message in Kohana 3

I have to show message after insert some data in database. I'm using Kohana. Is there a way to do that with flash messages? It's better than header refresh.
Well sort of. You could use the Session::get_once() function. But this only let you retrieve a variable once, and you cannot use it again in the same request. While you want a flash message to persist a full request cycle. To manage that you'll need a wrapper class, something like this.
class Flash {
private $session;
private $messages = array();
private static $_instance; // Singleton object
public static function instance() {
if ( ! isset( self::$_instance ) ) {
self::$_instance = new Flash();
}
return self::$_instance;
}
private function __construct() {
$this->session = Session::instance();
$this->messages['current'] = $this->session->get_once('flash');
if( ! is_array($this->messages['current'] ) ) {
$this->messages['current'] = array();
}
}
public function add( $key, $message === null ) {
if ( is_null( $message ) ) {
$message = $key;
$key = null;
}
$this->messages['new'][$key] = $message;
$this->session->set('flash', $this->messages['new'] );
return true;
}
public function get( $item = null ) {
if( $item === null ) {
return $this->messages['current'];
}
if( ! array_key_exists($item, $this->messages['current']) ) {
return null;
}
return $this->messages['current'][$item];
}
}
Usage:
$flash = Flash::instance();
$flash->add('A random message');
$flash->add('some_key', 'Some message');
$flash->get(); // array( 0 => 'A random message', 'some_key' => 'Some message')
$flash->get('some_key'); // 'A Random message'
What it does basically is on initialization it retrieves the current message from the session, using the get_once() function. The variable is nou out of the Session object, so it will only last this request. Everytime you add a variable, it will immediately persisted to the Session object.
There is just one problem; if you are using ajax calls, the messages will only be available on the initial php request, not on subsequent ajax calls. And there is also no restriction whatsoever on what kind of variable you are storing (but it must be serializable). You'll have to build in some checks for that too.
warning: the class is not tested, so it would surprise me if you do not get a syntax error ;)
And to go a step further: you would need an extra refresh anyway. The request flow should be like this imo:
Request 1: User is presented form
Request 2: User posts the form, which is processed. Data is inserted in database. When done, user is redirected
Request 3: A confirmation page is shown (can be "thank you", or the detail page, whatever).
You would set the flash message in request 2, and show it in 3. I would not directly show the thank you page on request 2, because when the user refreshes, the form will be posted again.
Use this module. Works perfectly :)

mocking the populate method using mockgoose for mongoose (mongodb library for node.js) is null

Having trouble debugging an issue that mockgoose has for populating a property with fields set. Yads mockgoose http://github.com/yads/Mockgoose fork solved the bug of making the populate option work, but if you specify fields it returns a null for the populated property. I tried looking through the source code and stepping through with the debugger but not sure where to look. I can see in the debugger that the populate option triggers a call to get the child element - and I see the call made returns the right child result with the correct fields, but when the parent element finally comes back it has the property to the child element set to null.
The query:
Posts.findById(foo).populate('createdBy', {fname:1, lname:1});
Incorrectly returns a post with post.createdBy = null. Omitting the fields parameter of fame, lname, somehow makes it work again with post.createdBy returning the full object.
Following are some excerpts from the code - though I'm not sure those are the right places to look.
collections.js
this.find = function (conditions, options, callback) {
var results;
var models = db[name];
if (!_.isEmpty(conditions)) {
results = utils.findModelQuery(models, conditions);
} else {
results = utils.objectToArray(utils.cloneItems(models));
}
results = filter.applyOptions(options, results);
if (results.name === 'MongoError') {
callback(results);
} else {
var result = {
toArray: function (callback) {
callback(null, results);
}
};
callback(null, result);
}
};
util.js
function cloneItems(items) {
var clones = {};
for (var item in items) {
clones[item] = cloneItem(items[item]);
}
return clones;
}
function cloneItem(item) {
return _.cloneDeep(item, function(value) {
// Do not clone items that are ObjectId objects as _.clone mangles them
if (value instanceof ObjectId) {
return new ObjectId(value.toString());
}
});
}
And here's a conversation about the issue
https://github.com/mccormicka/Mockgoose/pull/90

drupal_get_form : Manual call to render a form isn't working

Menu Callback
function content_form_select($id, $sid){
$type = check_content_type($sid);
if($type == 'video')
// Render content edit form
return drupal_get_form('content_video_form', $id, $sid);
else if($type == 'gallery')
// Render content edit form
return drupal_get_form('content_gallery_form', $id, $sid);
}
Video Form Generator
function content_video_form($id=null, $sid=null){
return array('#value' => 'Video form is getting rendered.');
}
Gallery Form Generator
function content_gallery_form($id=null, $sid=null){
return array('#value' => 'Gallery form is getting rendered.');
}
It does not render form this way
The drupal_get_form expects to receive a $form array, which then contains the form elements. Using one of your example functions above, the following change works for me:
function content_gallery_form($id=null, $sid=null){
$form['example'] = array('#value' => 'Gallery form is getting rendered.');
return $form;
}

Resources