Access PHP protected properties - php

Hi there I have a class : AbstractEntityType with a protected property :
abstract class AbstractEntityType extends AbstractType {
protected static $lists = null;
public function __construct($lists = array()) {
AbstractEntityType::$lists = $lists;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setRequired(array(
'temp', 'statut'
));
}
}
Here is another class extending the previous one :
class MyType extends AbstractEntityType {
....
}
I use a factory to create MyType class:
class SimpleFormTypeFactory {
public function createType($entity_type, $entity_stub, $lists = null) {
$type = null;
switch($entity_type) {
....
case SOMENUMTYP:
$type = new MyType($lists);
break;
}
}
I tested it locally with php 5.4 and windows with no problem but on the server (linux and php 5.3) I have this error :
Error: Cannot access protected property MyType::$lists
What is going on ? a php bug ?
Thank you

The property is protected, so you can never do this:
public function __construct($lists = array()) {
AbstractEntityType::$lists = $lists;
^^^^^^^^^^^^^^^^^^^^^^^^^^ Not allowed for a protected property, regardless where you are
}
However, when you are inside your class, you can access it directly:
public function __construct($lists = array()) {
self::$lists = $lists;
}

Related

why does file_put_contents insert 2 rows into json file?

I have a JSON file as my database, I wrote this function for creating a new user row into the file:
function create(array $data)
{
$tableFilePath = __DIR__ . "/storage/jsondb/users.json";
$fileData = json_decode(file_get_contents($tableFilePath));
$fileData[] = $data;
$fileDataJson = json_encode($fileData);
file_put_contents($tableFilePath, $fileDataJson);
}
create(['id' => rand(1, 100), 'name' => 'user' . rand(1, 100)]);
The problem is that when I call this function, I expect it inserts 1 row but it inserts 2 rows into the JSON file.
UPDATE:
my JSON file before running the code is an empty array:
[]
After running the code:
[{"id":28,"name":"user-3"},{"id":68,"name":"user-78"}]
as you can see, I executed the code one time, but it inserted two records into the JSON file.
UPDATE-3
I summarized my code because I wanted others can read it easily.
now it's my whole class that I wrote.
here is my interface:
interface CrudInterface
{
public function create(array $data) : int;
public function find(int $id): object;
public function get(array $columns,array $where):array;
public function update(array $data,array $where):int;
public function delete(array $where):int;
}
here I have abstract class BaseModel that implements CrudInterface:
abstract class BaseModel implements CrudInterface
{
protected $connection;
protected $table;
protected $pageSize = 10;
protected $attributes = [];
protected $primaryKey = 'id';
protected function __construct()
{
# if mysql => set mysql connection
}
protected function getAttribute($key)
{
if(!$key || array_key_exists($key, $this->attributes)){
return null;
}
return $this->attributes[$key];
}
}
here JsonBaseModel that extends BaseModel:
class JsonBaseModel extends BaseModel
{
private $dbFolder;
private $tableFilePath;
public function __construct()
{
$this->dbFolder = BASE_PATH . 'storage/jsondb/';
$this->tableFilePath = $this->dbFolder . $this->table . '.json';
}
private function readTable()
{
$fileData = json_decode(file_get_contents($this->tableFilePath));
return $fileData;
}
private function writeTable($fileData){
$fileDataJson = json_encode($fileData);
file_put_contents($this->tableFilePath, $fileDataJson);
}
public function create(array $newData): int
{
$fileData = $this->readTable();
$fileData[] = $newData;
$this->writeTable($fileData);
return $newData[$this->primaryKey];
}
}
and here I have class User that extends JsonBaseModel:
class User extends JsonBaseModel
{
protected $table = 'users';
}
then I made an instance of User class and call it's create() function here:
$data = ['id' => rand(1, 100),'name' => "user-".rand(1, 100)];
$userModel = new User();
$userModel->create($data);
You're passing in an array with the user details, then adding it to the current contents.
If there is already a entry in your file, you'll then have 2 entries.
Make sure that users.json is empty first.

PHPUnit - Mockery::mock vs Mockery::namedMocks

I'm writing PHPUnit Test with Mockery, (PHP v5.6.32, PHPUnit 3.7.21, Mockery dev-master) and found something which I can't understand about using Mockery::mock and Mockery::namedMocks.
My code is below, and the questions are:
Am I correct to use in LegendTest.php the Mockery::namedMock() instead of Mockery::mock() for SignalsCollection object?
Regarding to documentation about namedMock, I expect that frist argument is the Class name (SignalsCollection) and the second argument should be the extends statement (\ArrayObject) - but in my case I'm getting an error: Mockery\Exception\BadMethodCallException : Received Charts\SignalsCollection::getIterator(), but no expectations were specified, so I'm giving only one argument and this works fine. Why? What am I doing wrong? I'm confused.
Did I missed something in this test case or should I do something different to make tests better?
Signal.php:
class Signal
{
protected $id = 0;
protected $colName = '';
protected $tableName = '';
public function getId()
{
return $this->id;
}
public function setColName($colName)
{
$this->colName = $colName;
return $this;
}
public function setTableName($tableName)
{
$this->tableName = $tableName;
return $this;
}
}
SignalsCollection.php:
class SignalsCollection extends \ArrayObject
{
}
Legend.php
class Legend
{
protected $signalsCollection = null;
protected $graphModel = null;
public function __construct(SignalsCollection $signalsCollection, GraphModel $graphModel)
{
$this->signalsCollection = $signalsCollection;
$this->graphModel = $graphModel;
}
public function getSignalsCollection()
{
return $this->signalsCollection;
}
public function removeSignal(Signal $signal)
{
foreach ($this->signalsCollection as $key => $item) {
if ($item->getId() === $signal->getId()) {
$this->signalsCollection->offsetUnset($key);
break;
}
}
}
}
LegendTest.php:
class LegendTest extends \PHPUnit_Framework_TestCase
{
protected function tearDown()
{
parent::tearDown();
Mockery::close();
}
public function testRemoveSignal()
{
$testSignal = Mockery::mock('\Charts\Signal')
->shouldReceive('setColName', 'setTableName')
->andReturn(Mockery::self())
->mock();
$testSignal
->setColName('testColumnName')
->setTableName('testTableName');
$testSignalSecond = Mockery::mock('\Charts\Signal')
->shouldReceive('setId', 'setColName', 'setTableName')
->andReturn(Mockery::self())
->mock();
$testSignalSecond
->setId(1)
->setColName('testColumnName')
->setTableName('testTableName');
$signalsCollection = Mockery::namedMock('\Charts\SignalsCollection')
->shouldReceive('append', 'offsetUnset')
->andReturn(Mockery::self())
->mock();
$signalsCollection
->append($testSignal)
->append($testSignalSecond);
$legend = new Legend($signalsCollection, Mockery::mock('\Charts\GraphModel'));
$this->assertEquals($signalsCollection, $legend->getSignalsCollection());
$legend->removeSignal($testSignalSecond);
$signalsCollection->offsetUnset(1);
$this->assertEquals( $signalsCollection, $legend->getSignalsCollection() );
}
}

Google Maps Engine API Hello World Example in PHP causing MapItem not found

I am trying to work through getting the PHP client for Google Map to work correctly.
I've downloaded a local copy of the GoogleAPI PHP Client from GitHub:https://github.com/google/google-api-php-client.
I am running PHP v5.4 on IIS8. The GoogleAPI was installed in the PHP Include folder, under GoogleAPI.
PHP works correctly with all my other scripts.
I am trying get the example to work from Maps-Engine Documentation.
<?php
ini_set('display_errors','on');
require('GoogleAPI/autoload.php');
//require_once 'GoogleAPI/src/Google/Client.php';
//require_once 'Google/Service/MapsEngine.php';
$apiKey = "API Key";
$client = new Google_Client();
$client->setApplicationName("Google-PhpMapsEngineSample/1.0");
$client->setDeveloperKey($apiKey);
$service = new Google_Service_MapsEngine($client);
$optParams = array('maxResults' => 500, 'version' => 'published');
$results = $service->tables_features->listTablesFeatures("12421761926155747447-06672618218968397709", $optParams);
print_r($results);
?>
The only changes to the code example were the API Key, load the Google Autoloader and comment out the require_once directives.
The output I receive is:
Fatal error: Class 'Google_Service_MapsEngine_MapItem' not found in C:\Program Files (x86)\PHP\v5.4\includes\GoogleAPI\src\Google\Service\MapsEngine.php on line 4702
MapsEngine:4702 extends the Google_Service_MapsEngine_MapItem class. The Google_Service_MapsEngine_MapItem class extends the Google_Model class defined in Model.php file.
Hi I had the same problem.
There is a bug in the google-api-php-client/src/Google/Service/MapsEngine.php file. The class Google_Service_MapsEngine_MapFolder which exends the Google_Service_MapsEngine_MapItem is declared before the class Google_Service_MapsEngine_MapItem is declared.
I switch the order of the 2 classes in the MapsEngine.php file and that fixed the problem. This shows the correct order for the classes.
class Google_Service_MapsEngine_MapItem extends Google_Model
{
protected $internal_gapi_mappings = array(
);
public $type;
public function setType($type)
{
$this->type = $type;
}
public function getType()
{
return $this->type;
}
}
class Google_Service_MapsEngine_MapFolder extends Google_Service_MapsEngine_MapItem
{
protected $collection_key = 'defaultViewport';
protected $internal_gapi_mappings = array(
);
protected $contentsType = 'Google_Service_MapsEngine_MapItem';
protected $contentsDataType = 'array';
public $defaultViewport;
public $expandable;
public $key;
public $name;
public $visibility;
protected function gapiInit()
{
$this->type = 'folder';
}
public function setContents($contents)
{
$this->contents = $contents;
}
public function getContents()
{
return $this->contents;
}
public function setDefaultViewport($defaultViewport)
{
$this->defaultViewport = $defaultViewport;
}
public function getDefaultViewport()
{
return $this->defaultViewport;
}
public function setExpandable($expandable)
{
$this->expandable = $expandable;
}
public function getExpandable()
{
return $this->expandable;
}
public function setKey($key)
{
$this->key = $key;
}
public function getKey()
{
return $this->key;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function setVisibility($visibility)
{
$this->visibility = $visibility;
}
public function getVisibility()
{
return $this->visibility;
}
}

Dynamic extended models method not run - PHP

I wrote a class for module creating. That run correctly except that model object.
Model class :
class Model{
public static $db;
protected $_table_name;
public function __construct() {
self::$db =& DB::singleton();
}
public function get($rows="*",$where=null,$page_no=null,$limit=null,$order_by=null,$table_name=null){
if(!isset($table_name)||empty($table_name)){
self::$db->table=$this->_table_name;
}else{
self::$db->table=$table_name;
}
self::$db->rows = $rows;
self::$db->limit=$limit;
self::$db->where=$where;
self::$db->page_no=$page_no;
self::$db->order_by=$order_by;
return self::$db->read();
}
public function delete($id,$table){
self::$db->table = $table;
self::$db->where ="id='{$id}'";
self::$db->delete();
return 1;
}
public function drop_table($table){
self::$db->table=$table;
self::$db->drop_table();
return 1;
}
public function get_module_name(){
return $this->_table_name;
}
public function set_table($table_name){
$this->_table_name=$table_name;
}
}
Extended class :
class m_publication_categories extends model
{
protected $_table_name = 'publication_categories';
}
Controller :
class Controller{
public $db;
public $model;
public function __construct(){
core::$theme->setup();
$model_class_name = "m_".get_called_class();
$this->model=new $model_class_name();
}
public function listAction(){
$module_name = $this->model->get_module_name();
$module_model = new m_modules();
/**moduleinfo*/
$module = $module_model->get("*","table_name='{$module_name}'");
$module = $module[0];
$module_columns = $module_model->list_fields($module->id);
$data = $this->model->get();
print_r($data);die;
$this->assign('data',$data);
$this->assign('module_columns' , $module_columns);
$this->assign('module',$module);
$this->display('list_module_data','modules');
}
}
I want use model::get method from controller $this->model->get but that not work correctly. But if i print_r $this->model in controller , return result like that :
m_publication_categories Object ( [_table_name:protected] => publication_categories )
This means code in extends model class, but why not enter main model class ?
thanks.

workaround for multiple inheritances in PHP?

In a lot of my PHP classes, I have this code:
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
The point is so that outside code can know if an object has an error state, what the string of the error is, etc. But to have this exact code in a bunch of different classes is repetitious!
I'd love to have a dual-extension where I could do
class childClass extends parentClass, error {
...
}
And have those properties and methods inborn, But PHP doesn't support multiple inheritances. What I'm thinking about doing is creating an error class that exists inside each class. If I make it public, I can call it directly through the object
if ( $myObject->error->isError() ) {...}
but wouldn't that also make its error status settable from outside the containing class,
$myObject->error->setError("I shouldn't be doing this here");
which I would rather avoid?
Or I could write 'gateway' functions in the containing class, which do the appropriate calls on the error object, and prevent setting the error status from outside,
class childClass extends parentClass {
private $error;
public function __construct(...) {
...
$error = & new error();
...
}
public function isError() {...}
public function getError() {...}
public function getErrorCode() {...}
private function setError() {...}
...
}
but that leads to (some of) the code duplication that I'm trying to avoid.
What's the optimal solution here? I'm trying to have functionality for error statuses for a number of objects, so that the outside world can see their error state, with minimal repetition.
Use composition instead of inheritance.
class Errors {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
And now use a private instance variable to refer to it:
class childClass extends parentClass {
private $errors = new Errors();
...
}
The private visibility prevents you from referencing $errors outside of the class.
There's also no need to create isError(), getError(), etc. inside childClass (and therefore no need to worry about code duplication). Simply call $this->errors->isError(), $this->errors->getError(), etc. If you still wanted to require those methods to be implemented though, as suggested below, you could specify an interface.
You could also abuse the __call magic method to do the same thing:
public function __call($name, array $arguments) {
$name = strtolower($name);
if (isset($this->methods[$name])) {
array_unshift($arguments, $this);
return call_user_func_array($this->methods[$name], $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
Note that I said abuse... Ideally, I'd think of a different architecture rather than having all these "common methods" everywhere. Why not use an exception instead of checking $foo->isError? If that's not appropriate, why not decorate a class?
class Errors
protected $object = null;
public function __construct($object) {
$this->object = $object;
}
public function __call($method, array $arguments) {
$callback = array($this->object, $method);
if (is_callable($callback)) {
return call_user_func_array($callback, $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
public function __get($name) { return $this->object->$name; }
public function __set($name, $value) { $this->object->$name = $value; }
// Your methods here
public function isInstance($name) { return $this->object instanceof $name; }
}
Then just "wrap" your existing object in that class:
$obj = new Errors($obj);
$obj->foo();
As of PHP 5.4, you can use Traits.
For example you could make Trait called ErrorTrait like this:
trait ErrorTrait {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
Then you would define your child class like this:
class childClass extends parentClass {
use ErrorTrait;
...
}
Traits work basically like copy/paste so all of the code in the trait would be available within the class (without the code duplication).

Categories