Laravel passed argument - php

I have some problems with my Laravel app. I'm trying to make scraper and It looks like this.
<?php
namespace App\Http\Controllers;
use App\Scraper\Amazon;
use Illuminate\Http\Request;
class ScraperController extends Controller
{
public $test;
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$this->test = new Amazon();
return $this->test;
}
As you can see I have created new folder inside app that is called Scraper, and I have Amazon.php file that looks like:
<?php
namespace App\Scraper;
use Goutte\Client;
class Amazon
{
public string $test = '';
public function __construct()
{
return "test";
}
public function index()
{
$client = new Client();
$crawler = $client->request('GET', 'https://www.amazon.co.uk/dp/B002SZEOLG/');
$crawler->filter('#productTitle')->each(function ($node) {
$this->test = $node->text()."\n";
});
return $this->test;
}
}
And this is always returning error like
TypeError: Argument 1 passed to
Symfony\Component\HttpFoundation\Response::setContent() must be of the
type string or null, object given,
What am I doing wrong?

I believe the problem is returning the object itself (return $this->test), you should use return response()->json([$this->test]);

return var_dump($node->text()); before return $this->test to be sure test() is returning the expected value.

In my case I had a post request to a function
$contest = Contest::with('contestRatings')->where('id', '=', $contest_id);
return $contest;
I needed get() to make it work
$contest = Contest::with('contestRatings')->where('id', '=', $contest_id)->get();

This issue resolved for me when I added ->get().
Try:
return $this->test->get();

Use this syntax to return your response.
return response()->json($this->test);

Related

Is it possible to invoke an instance of a class whose name is passed as a variable?

I'm developing in Laravel 9, though I assume this is Php-specific. Example below of what I'm trying to achieve: Imagine I have a controller named HomeController.php with a getData() method that returns something I need...
<?php
namespace App\Http\Controllers;
class HomeController
{
public function getData()
{
return [my data]
}
}
And I want to be able to call that class and method in a dynamic way, and assign my data to $data...
<?php
use App\Http\Controllers\HomeController;
class Example
{
public $className = 'HomeController';
public $method = 'getData';
public function index()
{
$instance = new $this->className;
$method = $this->method;
$data = $instance->$method();
}
}
I have a variation of this setup in my application, and it's not working. I get the following error: Class "HomeController" not found.
If I replace $this->className with HomeController it works. Keep in mind $className will be passed from elsewhere, I want to avoid hard-coding class names into my Example class.
It is true that I will still need to include them all at the top anyway, but I just want to know if it's possible to pass a class name like that. Unless there's a way to dynamically include those too, but I doubt it.
Edit: Tim's answer in the comments worked great. Here is a fixed version:
<?php
use App\Http\Controllers\HomeController;
class Example
{
public $className = 'App\\Http\\Controllers\\HomeController'; // Change 1
public $method = 'getData';
public function index()
{
$instance = app()->make($this->className); // Change 2
$method = $this->method;
$data = $instance->$method();
}
}

Access class methods

I'm having a problem. I have a unit test that is trying to access methods from a class. My unit test is as follows
public function testReverseArraySuccess()
{
$data = "This is a test.";
$output = (new Reverse)
->setInput($data)
->get();
$this->assertEquals(['test', 'a', 'is', 'This'], $output);
}
My class is a follows
class Reverse
{
public $input;
/**
*
* #param $data
*/
public function setInput($data) {
$this->input = $data;
}
/**
*
*#return void
*/
public function get()
{
return $this->input;
}
}
How can I setup my class so that my Test will pass?
The error I get when I run the test is.
Error : Call to a member function get() on null
setInput isn't chainable since it's not returning an instance of itself. It's a void function that returns null by default that's why you're getting that error message. Update setInput to return an instance of the class to make it chainable.
public function setInput($data) {
$this->input = $data;
return $this;
}
Now get will return whatever value is passed to the input property, here's a working demo.
Then it's a matter of reversing the input, but I'll leave that up OP. 👍
You need to call get data directly after set data by instance of Reverse class.
public function testReverseArraySuccess() {
$data = "This is a test.";
$output = new Reverse;
$output->setInput($data);
$this->assertEquals(['test', 'a', 'is', 'This'], $output->get());
}

Codeigniter 4 - get instance in helper function

how can i get in ci4 instance into helper function? $CI =&get_instance(); <- that was in version 3, how does this go in version Codeigniter 4?
I made a gist for it. here is a way to do it.
Create a helper file, you can name it whatever you want.
Add the following codes to the helper you just created.
Content of the helper file: i.e: utility_helper.php
<?php
$CI_INSTANCE = []; # It keeps a ref to global CI instance
function register_ci_instance(\App\Controllers\BaseController &$_ci)
{
global $CI_INSTANCE;
$CI_INSTANCE[0] = &$_ci;
}
function &get_instance(): \App\Controllers\BaseController
{
global $CI_INSTANCE;
return $CI_INSTANCE[0];
}
Call register_ci_instance($this) at the very beginning of your base controller
Now you may use get_instance() where ever you want just like CI3: $ci = &get_instance()
There are three notes I want to mention
I tested on PHP8 only.
I'm not sure if & is needed when calling get_instance. however, you have the option to use any form you want. so calling $ci = get_instance() is ok too, but you may do $ci = &get_instance() as you wish.
Make sure you change \App\Controllers\BaseController to something appropiate(i.e: your base controller). type hinting is great since IDEs understand them.
Create a common helper to keep the controller instance. Suppose here it is common_helper.php
$CI4 = new \App\Controllers\BaseController;
function register_CI4(&$_ci)
{
global $CI4;
$CI4 = $_ci;
}
In your BaseController
public $user_id;
protected $helpers = ['form', 'url', 'common']; // Loading Helper
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
parent::initController($request, $response, $logger);
register_CI4($this); // Registering controller instance for helpers;
$this->user_id = 4;
}
Now you will get the controller instance in all other helpers. Suppose a new heper user_helper as
function show_user_id()
{
global $CI4;
echo $CI4->user_id; // Showing 4
}
I tested it in PHP Version: 8.0.6
For me, this is the best solution for me:
if (!function_exists('getSegment'))
{
/**
* Returns segment value for given segment number or false.
*
* #param int $number The segment number for which we want to return the value of
*
* #return string|false
*/
function getSegment(int $number)
{
$request = \Config\Services::request();
if ($request->uri->getTotalSegments() >= $number && $request->uri->getSegment($number))
{
return $request->uri->getSegment($number);
}
else
{
return false;
}
}
}
source: https://forum.codeigniter.com/thread-74755.html
I get it (using CodeIgniter4):
in controller:
helper('login');
$isLog=isLogged($this,"user","passwd");
if($isLog)
....
else
....
in helper:
use App\Models\Loginmodel as Loginmodel;
function isLogged($ci,$e,$c){
$ci->login = new Loginmodel;
$ci->login->Like('paassword',$c);
$id=$ci->login->select('id')->where('username',$e)->findAll();
return $id;
}
I hope this helps.

Object collection classes or not

I'm trying to decide whether to create many classes for each content type I have in my application/database or just stick with procedural code.
Version 1:
make a class for each object collection:
class App{
protected $user_collection;
function getUserCollection(){
if(!isset($this->user_collection)
$this->user_collection = new UserCollection($this);
return $this->user_collection;
}
// ...
}
class UserCollection{
function __construct(App $app){
$this->app = $app;
}
function getUser($user){
return new User($this->app, $user);
}
function getUsers($options){
$users = $this->app->getDatabase()->query($options);
foreach($users as &$user)
$user = new User($this, $user);
return $users;
}
// ...
}
which I'm using like:
$app = new App();
echo $app->getUserCollection()->getUser('admin')->email_address;
version 2:
keep all methods in a single class
class App{
function getUsers($options){
$users = $this->getDatabase()->query($options);
foreach($users as &$user)
$user = new User($this, $user);
return $users;
}
function getUser($user){
return new User($this, $user);
}
// ...
}
used like:
$app = new App();
echo $app->getUser('admin')->email_address;
version 3:
make getUsers() a a static method in the "User" class (the method instantiates a new User object):
$app = new App();
echo User::getUser($app, 'admin')->email_address;
Which way should I go? The "user" object is just an example, App has other objects too, like "database", "pages" etc.
I would use your version 1, but I would make getUser() and getUsers() methods of App.
This gets rid of the awkward getUserCollection() call, because instead inside the getUser() and what not you just call $this->user_collection.
Personnaly, I often used the second one with method like this:
class user {
/**
* Load object from ...
*/
public function load($userId) {}
/**
* Insert or Update the current object
*/
public function save() {}
/**
* Delete the current object
*/
public function delete() {
// delete object
// Reset ID for a future save
$this->UserID = null;
}
/**
* Get a list of object
*/
public static function getList() {
// Make your search here (from DB)
// Put rows into new "SELF" object
$list = array();
foreach($rows as $row) {
$obj = new self();
$obj->populate($row);
$list[$obj->UserID] = $obj; // Associative array or not...
}
}
}
Like you can see, I set my "getList" function static to simply access like this:
$listUsers = user::getList();
OK, it's very simple but work in most case of simple app.

MockObject property gets cleared after constructor

Hi guys i'm currently writing a test for a function inside a class in my project.
function theTestFunction()
{
$companyMock = $this->createMock(Company::class);
$companyMock->method('getUser')->willReturn(new User());
$companyMock->method('isActive')->willReturn(false);
$companyMock->expects($this->once())->method('setActive')->with(true)->willReturn($companyMock);
$manager = $this->getMockBuilder(CompanyManager::class)
->setMethods(['updateNewsletter'])
->setConstructorArgs([$companyMock])
->getMock();
$manager->expects($this->once())->method('updateNewsletter');
$manager->switchActivation();
}
But i don't understand why my stubbed method getUser() (called in the updateNewsletter()) returns null when i trigger the original function switchActivation() which is something like this
function switchActivation() : Company
{
$this->company = $this->company->setActive(!$this->company->isActive());
$this->company->save();
$this->updateNewsletter();
return $this->company;
}
This is the function failing the test
function updateNewsletter()
{
$user = $this->company->getUser();
// Do some other stuff...
}
instead of
->willReturn($companyMock)
use
->will($this->returnSelf())
Cf. https://phpunit.readthedocs.io/en/7.4/test-doubles.html#test-doubles-stubs-examples-stubtest4-php

Categories