mongodb / laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)
https://www.mongodb.com/docs/drivers/php/laravel-mongodb/
MIT License
7.01k stars 1.43k forks source link

Call to a member function all() on array #978

Closed gp187 closed 6 years ago

gp187 commented 8 years ago

Model:

use Jenssegers\Mongodb\Eloquent\Model as Moloquent;
class Product extends Moloquent
{
    protected $connection="mongodb";
    protected $dates = [
        'created_at', 'last_modified'
    ];
    protected $collection="products";
}

Controller:

class ProductCTRL extends Controller
{
    public function index(Request $request, $id)
    {
        $products = Product::where('cid', '=', $id)->get();
        return parent::formatResponse($products, true, 200);
    }
}

After running a composer update, gives out this error:

FatalThrowableError in Builder.php line 613:
Call to a member function all() on array
1. in Builder.php line 613
2. at Builder->getModels(array('*')) in Builder.php line 318
3. at Builder->get() in /srv/API/app/Http/Controllers/ProductCTRL.php line 44

line 44 is where the ->get() is

If I do it like this, it works:

class ProductCTRL extends Controller
{
    public function index(Request $request, $id)
    {
        $db = DB::connection('mongodb')->collection("products");
        $products = $db->where('cid', '=', $id)->get();

        return parent::formatResponse($products, true, 200);
    }
}
pi0 commented 8 years ago

Would you provide your composer.json ?

gp187 commented 8 years ago

Here it is

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.6.4",
        "laravel/framework": "5.3.*",
        "jenssegers/mongodb": "^3.0",
        "guzzlehttp/guzzle": "^6.2",
        "predis/predis": "^1.1",
        "symfony/finder": "^3.1",
        "symfony/event-dispatcher": "2.8.9",
        "rocket-code/shopify": "^2.0"
    },
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~5.0",
        "symfony/css-selector": "3.1.*",
        "symfony/dom-crawler": "3.1.*",
        "laravel/homestead": "^3.0",
        "squizlabs/php_codesniffer": "^2.6"
    },
    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },
    "autoload-dev": {
        "classmap": [
            "tests/TestCase.php"
        ]
    },
    "scripts": {
        "post-root-package-install": [
            "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ],
        "post-install-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postInstall",
            "php artisan optimize"
        ],
        "post-update-cmd": [
            "Illuminate\\Foundation\\ComposerScripts::postUpdate",
            "php artisan optimize"
        ]
    },
    "config": {
        "preferred-install": "dist"
    }
}
pi0 commented 8 years ago

@gp187 Latest version (which supports 5.3) is tagged as alpha so you have to explicitly change it to something like this: "jenssegers/mongodb": "^3.1.0-alpha"

gp187 commented 8 years ago

Thanks @pi0 . Works now. I just thought the ^3 would pick up on latest.

vrkansagara commented 8 years ago

@gp187 and @pi0 works fine thanks :+1:

jversmis commented 7 years ago

It seems I can't get this to work.

When using dev-master branch, I get the error: Call to a member function all() on array

The error is thrown in Illuminate\Database\Eloquent\Builder->getModels() This function is called by

return $query->get()->toArray();

where $query is an instance of JensSegers\Mongodb\Eloquent\Builder.

At the moment of writing, the getModels function looks like this:

public function getModels($columns = ['*'])
{
    return $this->model->hydrate(
        $this->query->get($columns)->all(),
        $this->model->getConnectionName()
    )->all();
}

Since $this->query->get($columns) return an array, $this->query->get($columns)->all() throws the error Call to a member function all() on array

Removing the ->all() from $this->query->get($columns)->all() fixes the issue.

When using a stable version (3.1.3 at the moment of writing), I run into the non-public operators issue.

Any ideas on how to solve this?

mohitbhatia1994 commented 7 years ago

Same problem as @jversmis @pi0

jversmis commented 7 years ago

Back from holidays :-)

Some extra info, I'm using this package standalone.

The class Jenssegers\Mongodb\Query\Builder check in the constructor if it should use collections or not.

    /**
     * Returns true if Laravel or Lumen >= 5.3
     *
     * @return bool
     */
    protected function shouldUseCollections()
    {
        if (function_exists('app')) {
            $version = app()->version();
            $version = filter_var(explode(')', $version)[0], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); // lumen
            return version_compare($version, '5.3', '>=');
        }
    }

Since the app function doesn't exist, shouldUseCollections returns null and arrays are used. For testing, I've added return true; as the first line in the above function and running unit tests gives all green results again.

I don't have a solution yet. I suppose a dirty solution could be to create an app function in my project and have app()->version(); return true. Not the prettiest solution but it would work for now.

Update Tested with this little function added to my code and everything seems to work fine now. Again, not the prettiest solution but it's acceptable for my situation at the moment.

function app()
{
    return new class {
        public function version()
        {
            return '5.4';
        }
    };
mohitbhatia1994 commented 7 years ago

@jversmis thanks for your input. would you mind telling me the right position to input the app() function. I am getting an syntax error when I included app function about shouldUseCollections.

jversmis commented 7 years ago

@mohitbhatia1994

You can add the function anywhere in your project. Don't add it in the plugin code since any update of the plugin will erase the code again.

If you use any kind of framework, maybe you can add it in the bootstrap file. I've added it in a utils folder in the root of the project and load it through the autoload > file option in my composer.json

mohitbhatia1994 commented 7 years ago

@jversmis understood. Still this line return new class { giving a syntax error.

jversmis commented 7 years ago

@mohitbhatia1994 anonymous classes are a PHP 7 feature.

You can just use a named class, instantiate it and it should work.

For more info: http://php.net/manual/en/language.oop5.anonymous.php

mohitbhatia1994 commented 7 years ago

@jversmis I am using php 5.6

jversmis commented 7 years ago

@mohitbhatia1994 in that case, just use a named class instead of an anonymous class

mohitbhatia1994 commented 7 years ago

@jversmis Is this right way to convert that code in php5.6?

class temp {
    public function version()
        {
            return '5.4';
        }
}

function app()
{
    return new temp();
};
jversmis commented 7 years ago

@mohitbhatia1994 Haven't tested it myself but that seems correct to me. Does it work?

dyfire commented 7 years ago

@mohitbhatia1994 u can do like this,

composer.json add "files": [ "app/helpers.php" ]

then add file app/helpers.php ,code like this, if (!function_exists('app')) { function app() { $normal = new Normal(); return $normal; }

class Normal
{
    public function version()
    {
        return '5.4';
    }
}

}

comoser update, then u find that it works.

ghost commented 7 years ago

same error.. composer.json

        {
            "require": {
                "maximebf/cachecache": "^1.0",  
                "erusev/parsedown": "^1.6", 
                "illuminate/database": "^5.2",
                "illuminate/events": "^5.2",
                "schnittstabil/csrf-tokenservice": "^1.0",
                "maximebf/debugbar": "^1.13", 
                "matthiasmullie/minify": "^1.3",
                "vlucas/valitron": "^1.4",
                "illuminate/pagination": "^5.2",
                "symfony/yaml": "^3.3",
                "rmccue/requests": "^1.7",
                "kamermans/docblock-reflection": "^1.0",
                "crada/php-apidoc": "^1.3",
                "overtrue/easy-sms": "^0.0.5",
                "jenssegers/mongodb": "^3.2" 

            },
            "autoload": {
                    "classmap": ["./framework/"] ,
                    "psr-4": { 
                        "modules\\": "./modules/",
                        "models\\": "./models/",
                        "cs\\": "./class/" 
                    }
            }
        }

user.php

   namespace models;
   use Jenssegers\Mongodb\Eloquent\Model as Eloquent;

   class user extends Eloquent { 
    protected $connection = 'mongodb';
            protected $collection = 'users';
            protected $dates = [
                'created_at', 'last_modified'
            ];

       }

       print_r(user::all() );

Fatal error: Uncaught Error: Call to a member function all() on array i

add mognodb.

    use Illuminate\Database\Capsule\Manager as Capsule;
    use Illuminate\Events\Dispatcher;
    use Illuminate\Container\Container;
    //https://laravel.com/docs/5.4/database
    //https://laravel.com/docs/5.4/eloquent
    class_alias('Illuminate\Database\Eloquent\Model','model');
    class_alias('Illuminate\Database\Capsule\Manager','db');
    $capsule = new Capsule;
    $config = config('db');
    /**
     * @desc 配置MYSQL
     */
    if($config){
            foreach($config as $k=>$v){
              $capsule->addConnection($v,$k);  
            }
    }
    // use Jenssegers\Mongodb\Eloquent\Model as Eloquent;
    if($config['mongodb']){   
            $capsule->getDatabaseManager()->extend('mongodb', function($config)
            {
                return new Jenssegers\Mongodb\Connection($config);
            }); 
    } 

    $capsule->setAsGlobal();
    $capsule->bootEloquent();
elfeffe commented 7 years ago

I have added this code just below my real class

class temp {
    public function version()
        {
            return '5.4';
        }
}

function app()
{
    return new temp();
};

And works good. I think it will also work if we use Database 5.3 instead of 5.4

"illuminate/database": "^5.3",