zf2 call a method from a Model in another Model - model-view-controller

I have a couple of modules in ZF2 project. Each module has different model classes performing different required functions. Now I have method in a model class of first module which I want to call in the model class of second module. Is it possible to do so? if yes, how?

This should be fairly simple. Firstly you need to include the two modules in your application.config.php
'modules' => array(
'Module1',
'Module2'
)
Then as a very basic example taken from your question:
<?php
namespace Module2\Model;
use Module1\Model\Class1;
class Class2
{
public function doSomething()
{
$class1 = new Class1();
$class1->doSomething();
}
}

Related

Repeat Mutators

I'm using several mutators that are basically the same on different models and within the same models, for different fields. eg: to tidy dates:
public function getStartShortDateAttribute()
{
return $this->start_time->format('d-m-y');
}
Is there a standard way to reuse the same mutator for several fields across models?
Use a trait, which is a way to reuse code across classes.
trait HasStartTimes {
public function getStartShortDateAttribute()
{
return $this->start_time->format('d-m-y');
}
}
Now you can use this trait in your class, with the use statement. When done it will include the traits function, in the classes that uses the trait. This is an design approach that is used already in Laravel, see AuthenticatesUsers.
class YourModel {
use HasStartTimes;
}

How to create class variables in a PHPSpec spec file that can be used for all examples in the spec

I have a PHPSpec class with many examples. I want to be able to create class variables in the spec class that can be used by any example function in the class.
Below is a very simplified version:
class ThingImTestingSpec extends ObjectBehavior
{
private $common_variables_array = [
'property_1' => value_1,
'property_2' => 'Value 2'
];
function it_finds_a_common_property()
{
$object_1 = new ConstructedObject;
$this->find_the_common_property($object_1)->shouldReturn($this->common_variables_array['property_1']);
}
}
The issue lies in how PHPSpec (cleverly) instantiates and references the class under test. References to $this in the spec methods actually refer to the test object, not the spec class itself.
But that means that trying to reference class variables using $this->class_variable references class variables on the test object, not the spec.
So. How to create a set of variables in the scope of the spec class itself that can be accessed by the examples at runtime?
Things I've tried:
Placing the class variables within a constructor – still can't be accessed by the examples
Using beConstructedWith – requires altering the class under test just so it can be tested. Not a clean solution.
When the common objects I want to reference are database records, I can reference them by id (or other properties) using Eloquent, building a collection or class object from the Model each time. This works, but is time-consuming, as I need to build the collection or object in every spec function. I'd like to build these collections and objects once, when the spec class is instantiated, and reference them throughout the class.
Things I haven't tried yet:
Creating a third object outside the scope of both the spec class and the class under test to house the universal objects and variables, which can be accessed by the spec class methods (the examples) at runtime. This solution could work, but it adds a layer to the specs that I'd like to avoid if there's a cleaner solution.
NB: I'm not looking for "alternatives" to going about testing in the way outlined above, unless they still suit the broader needs. The example is extremely pared down. In practice, I'm extending LaravelObjectBehavior (https://github.com/BenConstable/phpspec-laravel), creating records in a test database using the spec's constructor via Factory and Faker classes (https://github.com/thephpleague/factory-muffin), and destroying them after the test (League\FactoryMuffin\Facade::deleteSaved() in the spec's destructor). I want to be able to reference objects represented by the Model (and created by FactoryMuffin) in any number of spec functions, so I don't have to recreate these objects and collections in every spec function. And yes, I'm aware that this steps outside the realm of "spec" testing, but when an app is tethered to a model, objects that interact with the data layer are still "speccable", it can be argued.
I'm currently using phpspec 2.2.1 and Laravel 4.2
We currently use PHPSpec v3 in our software. Please use let method to declare common things. Quick example:
<?php
class ExampleSpec extends \PhpSpec\ObjectBehavior
{
private $example; // private property in the spec itself
function let()
{
$this->example = (object) ['test1' => 'test1']; // setting property of the spec
parent::let();
}
function it_works()
{
var_dump($this->example); // will dump: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
}
function it_works_here_as_well()
{
var_dump($this->example); // will dump same thing as above: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
$this->example = (object) ['test2' => 'test2']; // but setting here will be visible only for this example
}
function it_is_an_another_example()
{
var_dump($this->example); // will dump same thing first two examples: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
}
}
Found the answer. Explicitly declare the class variables as static and they can be accessed by the methods in the spec class:
class ThingImTestingSpec extends ObjectBehavior
{
private static $common_variables_array = [
'property_1' => value_1,
'property_2' => 'Value 2'
];
function it_finds_a_common_property()
{
$object_1 = new ConstructedObject;
$this->find_the_common_property($object_1)->shouldReturn($this::$common_variables_array['property_1']);
}
}
This is working for arrays as well as objects that represent database records built using Eloquent, e.g.
class LaravelAppClassImTestingSpec extends LaravelObjectBehavior
{
private static $Order_1;
function __construct()
{
$Order_1 = \Order::find(123);
}
function it_tests_a_thing()
{
//(the method has access to the static class variable via
//$this::$Order_1
}
}

Symfony validator

My question is related to symfony validator component. I don't use forms. And I want to move validation rules for each entity to separated class (like AuthorVlidator, BookingValidator etc.). How can I move it to separated classes and define rules?
Thanks.
Why would you like to move it to separated classes? With annotations it pretty easy to use it.
It's not a good idea to do it, but if you really want to do it in other classes, you could add this method in each classes that you want to validate:
class YourObject
{
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
YourObjectValidator::validate($this, $metadata);
}
}
And:
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
class YourObjectValidator
{
public static function validate(YourObject $object, ClassMetadata $metadata)
{
$metadata->addPropertyConstraint('name', new NotBlank());
}
}
If you want separate this logic for add validation depending on properties value, it's not the proper way to do it. You should read the doc, callback could be a solution.

Laravel - Extending Model

I've created a BaseModel class, which extends from Model. It seemed like everything was working fine, but now I've run into a problem when saving. I'm overriding the save() method in this BaseModel. I'd just like to add some attributes to the model before saving. So I do that, then call return parent::save($options);. The method signature is still the same: public function save(array $options = []).
It appears to be grabbing the name of the BaseModel class for the table name when performing the insert (it's using base_models as the table name), rather than the actual model that is being saved. Has anyone run into this before? What is the proper way of extending from the model class?
I originally created some traits to handle some extra functionality, but thought it would be a better idea to just create a base model and have my models extend from that instead.
In your model (the child one that extends the base model) add the table name explictly for example:
class SomeChildModel extends BaseModel {
// Manually set the table name
protected $table = 'table_name';
}
I realized that I previously had a static method that was creating an instance of itself using new self() and would set a few attributes, back when I was using the methods from a trait. It was fine before, but now since I moved the methods into the base model, that method was actually being called on the base model itself rather than the class that had the trait.
I was basically using the static method to instantiate the class, as I've read it's one way to avoid cluttering the constructor. But I just opted to do it in the constructor this time around since it made sense, so that was my solution.
Laravel will use snake case of the class name by default (the class where save method is called), if no $table instance variable is set. In your case it will use snake case of the BaseModel as a table name. You have two solutions:
Solution 1:
In classes which extends BaseModel add the $table instance variable as follow:
class User extends BaseModel {
protected $table = 'table_name'; // Your table name in the database;
}
Solution 2:
You can use Laravel Eloquent's Events, which allows you to hook into various points in the model's lifecycle.
You can hook into the save method as follow and make your changes. You can use these methods in your BaseClass, in traits, etc. For example in your BaseModel:
class BaseModel extends Model
{
/**
* Listen for save event
*/
protected static function boot()
{
parent::boot();
static::saving(function($model)
{
if ( ! $model->isValid()) {
return false;
}
});
}
}
The above will always call isValid before a model is saved into the storage. In this case it will return false and will not save the object.
For more info see the official docs here. Let me know if it isn't clear.

CodeIgniter, RedBeanPHP and FUSE - Models not recognized by FUSE

I too ran into the problem that FUSE won't work with CI and RBphp.
in APPPATH/application/core/ I have a base model called "MY_Model.php"
class MY_Model {}
class Base extends RedBean_SimpleModel {
// static methods
}
I have a derived class, like this, called "model_user.php" in APPPATH/application/models/:
class Model_User extends Base {
public function getData() {
return $this->bean->id;
}
}
And in the controller I load the model:
$this->load->model('Model_User');
The rb library is autoloaded via the autoload.php file.
After creating an object of the type Model_User with redbean, I still cannot access the getData() method.
I already read this question + answer asked here, but they didn't help me.
The problem was due to the naming convention. Whilst the table itself was called "users", the bean's name was "Model_User". So RedBean was looking for a "User" table in the database. Renaming the class to Model_Users, or renaming the table to "user" was the solution.

Resources