How to get data and set to a variable from libasynql

Discussion in 'Development' started by Atomization, Apr 17, 2019.

  1. Atomization

    Atomization Baby Zombie

    Messages:
    111
    i have a db which stores various player data, here im using `kills`

    i have a class which is used to get the kills that the player has from db
    PHP:
    class GetKills{
        private 
    $plugin;
        private 
    $kills;
        private 
    $uuid null;

        public function 
    __construct(){
            
    $this->plugin $plugin;
        }

        public function 
    getKills(Player $player){
            
    $this->query($player);
            return 
    $this->kills;
        }

        public function 
    query(Player $player){
            
    $this->uuid $player->getUniqueId()->toString();
            
    DataHandler::getDatabase()->executeSelect("select.kills", [
                
    'uuid' => (string)$this->uuid
            
    ], 
                function (array 
    $rows) {
                    foreach(
    $rows as $row){
                        
    $this->kills $row['kills'];
                    }
                });
        }
    }
    when i call `getKills()` it returns `NULL` instead of returning the value from db
    PHP:
    class Main extends PluginBase{
        private 
    $data;
        public function 
    onEnable(){
            
    $this->data = new GetKills($this);
        }

        public function 
    onCommand(/*command stuff*/){
            
    $sender->sendMessage("you have '"$data->getKills($sender) ."' kills!");
        }
    }
    because its NULL; the output is: "you have ' ' kills!" the value is just missing because its null

    So the main question being: why is it not setting and how do i set the value to $this->kill in the GetKills class?
     
  2. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,894
    GitHub:
    sof3
    The kills are set long after the command executed. That's the whole point of async - stuff runs later.
    Change the code to:

    PHP:
    class GetKills{
        private 
    $plugin;

        public function 
    __construct(){
            
    $this->plugin $plugin;
        }

        public function 
    getKills(Player $player, callable $callback){
            
    $this->query($player$callback);
        }

        public function 
    query(Player $player, callable $callback){
            
    $uuid $player->getUniqueId()->toString();
            
    DataHandler::getDatabase()->executeSelect("select.kills", [
                
    'uuid' => (string)$uuid
            
    ],
                function (array 
    $rows) use($callback) {
                    foreach(
    $rows as $row){
                        
    $kills $row['kills'];
                    }
                    
    $callback($kills);
                });
        }
    }

    PHP:
    class Main extends PluginBase{
        private 
    $data;
        public function 
    onEnable(){
            
    $this->data = new GetKills($this);
        }

        public function 
    onCommand(/*command stuff*/){
            
    $this->data->getKills($sender, function($kills) use($sender){
                
    $sender->sendMessage("you have '"$kills ."' kills!");
            });
        }
    }
    Async means "execute later". An analogy is like you request a book (data) from a book shop (libasynql). The book is out of stock (need to be downloaded), so it takes a few days for the book shop to order the book from the publisher (MySQL server). The book shop cannot give you the book (return data) directly. Instead, they ask you to give your home address (the $callback), and when the book arrives, the book store will send the book to your home (libasynql callback function).
    Your problem here is that when you get home (after calling the query function), you assume that the book already arrives, while it actually takes a few more days to arrive, so you get an empty mailbox (null variable).
     
    HimbeersaftLP and Atomization like this.
  3. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,894
    GitHub:
    sof3
    We are planning to make even more PocketMine stuff async in 4.x and/or 5.0, so it's important to learn how to handle async properly.
     
    HimbeersaftLP likes this.
  4. Atomization

    Atomization Baby Zombie

    Messages:
    111
    do you know of any resources that would help me understand async better?
     
  5. Atomization

    Atomization Baby Zombie

    Messages:
    111
    another question i have to ask is; how do i send the data elsewhere? not using $player->sendMessage(); like using forms.

    this code uses customui
    PHP:
    use xenialdan\customui\API as Form;
    use 
    xenialdan\customui\elements\Button;
    use 
    xenialdan\customui\windows\SimpleForm;

    class 
    FormHandler {
        
    /** @var int[] **/
        
    public static $uis = [];

        
    /** @var Main **/
        
    private $plugin;

        public static function 
    formSender(Player $player){
            
    $ui = new SimpleForm("title"$this->getKills($player, function($kills) use ($player) {/**/}));
            
    $button = new Button('Close');
            
    $ui->addButton($button);
            
    self::$uis['statsui'] = Form::addUI($this->plugin$ui);
            
    Form::showUIbyID($this->pluginself::$uis['statsui'], $player);
        }
     
    Last edited: Apr 18, 2019
  6. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,894
    GitHub:
    sof3
    After you understand the basic concepts of callback, you may find it easier to implement async logic with await-generator. But you have to understand the fact that you can't do async in constructors, and you can never return the value directly.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.